diff --git a/sql/chunk.sql b/sql/chunk.sql index 2aef03569a2..8ec9e0a99cb 100644 --- a/sql/chunk.sql +++ b/sql/chunk.sql @@ -59,10 +59,6 @@ CREATE OR REPLACE FUNCTION _timescaledb_functions.create_chunk( RETURNS TABLE(chunk_id INTEGER, hypertable_id INTEGER, schema_name NAME, table_name NAME, relkind "char", slices JSONB, created BOOLEAN) AS '@MODULE_PATHNAME@', 'ts_chunk_create' LANGUAGE C VOLATILE; --- change default data node for a chunk -CREATE OR REPLACE FUNCTION _timescaledb_functions.set_chunk_default_data_node(chunk REGCLASS, node_name NAME) RETURNS BOOLEAN -AS '@MODULE_PATHNAME@', 'ts_chunk_set_default_data_node' LANGUAGE C VOLATILE; - -- Get chunk stats. CREATE OR REPLACE FUNCTION _timescaledb_functions.get_chunk_relstats(relid REGCLASS) RETURNS TABLE(chunk_id INTEGER, hypertable_id INTEGER, num_pages INTEGER, num_tuples REAL, num_allvisible INTEGER) diff --git a/sql/compat.sql b/sql/compat.sql index ffa7ecb0992..a874a948da6 100644 --- a/sql/compat.sql +++ b/sql/compat.sql @@ -638,16 +638,6 @@ END$$ SET search_path TO pg_catalog,pg_temp; -CREATE OR REPLACE FUNCTION _timescaledb_internal.set_chunk_default_data_node(chunk regclass,node_name name) RETURNS boolean LANGUAGE PLPGSQL AS $$ -BEGIN - IF current_setting('timescaledb.enable_deprecation_warnings', true)::bool THEN - RAISE WARNING 'function _timescaledb_internal.set_chunk_default_data_node(regclass,name) is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version.'; - END IF; - RETURN _timescaledb_functions.set_chunk_default_data_node($1,$2); -END$$ -SET search_path TO pg_catalog,pg_temp; - - CREATE OR REPLACE FUNCTION _timescaledb_internal.show_chunk(chunk regclass) RETURNS TABLE(chunk_id INTEGER, hypertable_id INTEGER, schema_name NAME, table_name NAME, relkind "char", slices JSONB) LANGUAGE PLPGSQL AS $$ BEGIN IF current_setting('timescaledb.enable_deprecation_warnings', true)::bool THEN diff --git a/sql/updates/2.10.1--2.10.2.sql b/sql/updates/2.10.1--2.10.2.sql index 43e9c16040e..001c3a14215 100644 --- a/sql/updates/2.10.1--2.10.2.sql +++ b/sql/updates/2.10.1--2.10.2.sql @@ -1,7 +1,10 @@ DROP FUNCTION _timescaledb_internal.ping_data_node(NAME); +-- We only create stub here to not introduce shared library dependencies in update chains +-- the proper function definition will be created at end of update script when all functions +-- are recreated. CREATE OR REPLACE FUNCTION _timescaledb_internal.ping_data_node(node_name NAME, timeout INTERVAL = NULL) RETURNS BOOLEAN -AS '@MODULE_PATHNAME@', 'ts_data_node_ping' LANGUAGE C VOLATILE; +AS $$SELECT false;$$ LANGUAGE SQL VOLATILE; -- drop dependent views DROP VIEW IF EXISTS timescaledb_information.job_errors; diff --git a/sql/updates/2.11.2--2.12.0.sql b/sql/updates/2.11.2--2.12.0.sql index ca1f10bfc9b..f5a8af90fcd 100644 --- a/sql/updates/2.11.2--2.12.0.sql +++ b/sql/updates/2.11.2--2.12.0.sql @@ -99,7 +99,6 @@ ALTER FUNCTION _timescaledb_internal.calculate_chunk_interval(int, bigint, bigin ALTER FUNCTION _timescaledb_internal.chunks_in(record, integer[]) SET SCHEMA _timescaledb_functions; ALTER FUNCTION _timescaledb_internal.chunk_id_from_relid(oid) SET SCHEMA _timescaledb_functions; ALTER FUNCTION _timescaledb_internal.show_chunk(regclass) SET SCHEMA _timescaledb_functions; -ALTER FUNCTION _timescaledb_internal.set_chunk_default_data_node(regclass, name) SET SCHEMA _timescaledb_functions; ALTER FUNCTION _timescaledb_internal.get_chunk_relstats(regclass) SET SCHEMA _timescaledb_functions; ALTER FUNCTION _timescaledb_internal.get_chunk_colstats(regclass) SET SCHEMA _timescaledb_functions; @@ -129,6 +128,8 @@ DECLARE alter_job_set_hypertable_id, + set_chunk_default_data_node, + create_compressed_chunk, get_compressed_chunk_index_for_recompression, recompress_chunk_segmentwise, chunk_drop_replica, chunk_index_clone, chunk_index_replace, create_chunk_replica_table, drop_stale_chunks, chunk_constraint_add_table_constraint, hypertable_constraint_add_table_fk_constraint, diff --git a/sql/updates/2.5.2--2.6.0.sql b/sql/updates/2.5.2--2.6.0.sql index 2305a4f7dc9..c894e529371 100644 --- a/sql/updates/2.5.2--2.6.0.sql +++ b/sql/updates/2.5.2--2.6.0.sql @@ -28,13 +28,14 @@ SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.continuous_aggs DROP VIEW IF EXISTS timescaledb_information.continuous_aggregates; +-- create stub to not introduce shared library dependency CREATE FUNCTION @extschema@.delete_data_node( node_name NAME, if_exists BOOLEAN = FALSE, force BOOLEAN = FALSE, repartition BOOLEAN = TRUE, drop_database BOOLEAN = FALSE -) RETURNS BOOLEAN AS '@MODULE_PATHNAME@', 'ts_data_node_delete' LANGUAGE C VOLATILE; +) RETURNS BOOLEAN AS $$SELECT true;$$ LANGUAGE SQL VOLATILE; CREATE FUNCTION @extschema@.get_telemetry_report() RETURNS jsonb AS '@MODULE_PATHNAME@', 'ts_telemetry_get_report_jsonb' diff --git a/sql/updates/2.8.1--2.9.0.sql b/sql/updates/2.8.1--2.9.0.sql index ba8a2d05ed2..4ef09259a64 100644 --- a/sql/updates/2.8.1--2.9.0.sql +++ b/sql/updates/2.8.1--2.9.0.sql @@ -380,7 +380,7 @@ GRANT SELECT ON _timescaledb_catalog.dimension TO PUBLIC; -- end recreate _timescaledb_catalog.dimension table -- --- changes related to alter_data_node(): +-- only creating stub here to not introduce shared library dependencies CREATE INDEX chunk_data_node_node_name_idx ON _timescaledb_catalog.chunk_data_node (node_name); CREATE FUNCTION @extschema@.alter_data_node( node_name NAME, @@ -389,7 +389,7 @@ CREATE FUNCTION @extschema@.alter_data_node( port INTEGER = NULL, available BOOLEAN = NULL ) RETURNS TABLE(node_name NAME, host TEXT, port INTEGER, database NAME, available BOOLEAN) -AS '@MODULE_PATHNAME@', 'ts_data_node_alter' LANGUAGE C VOLATILE; +AS $$ SELECT NULL::name,NULL::text,NULL::int,NULL::name,NULL::bool; $$ LANGUAGE SQL VOLATILE; -- -- Rebuild the catalog table `_timescaledb_catalog.continuous_agg` @@ -488,9 +488,9 @@ ALTER TABLE _timescaledb_catalog.continuous_agg_migrate_plan ANALYZE _timescaledb_catalog.continuous_agg; --- changes related to drop_stale_chunks() +-- only create stub here to not introduce shared library dependency CREATE FUNCTION _timescaledb_internal.drop_stale_chunks( node_name NAME, chunks integer[] = NULL ) RETURNS VOID -AS '@MODULE_PATHNAME@', 'ts_chunks_drop_stale' LANGUAGE C VOLATILE; +AS '' LANGUAGE SQL VOLATILE; diff --git a/sql/updates/latest-dev.sql b/sql/updates/latest-dev.sql index 788da16c007..27e92f9d1bc 100644 --- a/sql/updates/latest-dev.sql +++ b/sql/updates/latest-dev.sql @@ -113,3 +113,6 @@ DROP PROCEDURE IF EXISTS timescaledb_experimental.move_chunk; DROP PROCEDURE IF EXISTS timescaledb_experimental.copy_chunk; DROP PROCEDURE IF EXISTS timescaledb_experimental.cleanup_copy_chunk_operation; +DROP FUNCTION IF EXISTS _timescaledb_functions.set_chunk_default_data_node; +DROP FUNCTION IF EXISTS _timescaledb_internal.set_chunk_default_data_node; + diff --git a/sql/updates/reverse-dev.sql b/sql/updates/reverse-dev.sql index 7db64c69991..8724e7a591a 100644 --- a/sql/updates/reverse-dev.sql +++ b/sql/updates/reverse-dev.sql @@ -337,3 +337,7 @@ CREATE PROCEDURE timescaledb_experimental.cleanup_copy_chunk_operation( operation_id NAME) AS '@MODULE_PATHNAME@', 'ts_copy_chunk_cleanup_proc' LANGUAGE C; +CREATE FUNCTION _timescaledb_functions.set_chunk_default_data_node(chunk REGCLASS, node_name NAME) RETURNS BOOLEAN +AS '@MODULE_PATHNAME@', 'ts_chunk_set_default_data_node' LANGUAGE C VOLATILE; + + diff --git a/src/chunk.c b/src/chunk.c index 98e506f3a8b..b0b8ad89f91 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -806,46 +806,6 @@ ts_chunk_create_table(const Chunk *chunk, const Hypertable *ht, const char *tabl if (uid != saved_uid) SetUserIdAndSecContext(saved_uid, sec_ctx); } - else if (chunk->relkind == RELKIND_FOREIGN_TABLE) - { - ChunkDataNode *cdn; - - if (list_length(chunk->data_nodes) == 0) - ereport(ERROR, - (errcode(ERRCODE_TS_INSUFFICIENT_NUM_DATA_NODES), - (errmsg("no data nodes associated with chunk \"%s\"", - get_rel_name(chunk->table_id))))); - - /* - * Use the first chunk data node as the "primary" to put in the foreign - * table - */ - cdn = linitial(chunk->data_nodes); - stmt.base.type = T_CreateForeignServerStmt; - stmt.servername = NameStr(cdn->fd.node_name); - - /* Create the foreign table catalog information */ - CreateForeignTable(&stmt, objaddr.objectId); - - /* - * Some options require being table owner to set for example statistics - * so we have to set them before restoring security context - */ - set_attoptions(rel, objaddr.objectId); - - /* - * Need to restore security context to execute remote commands as the - * original user - */ - if (uid != saved_uid) - SetUserIdAndSecContext(saved_uid, sec_ctx); - - /* Create the corresponding chunk replicas on the remote data nodes */ - ts_cm_functions->create_chunk_on_data_nodes(chunk, ht, NULL, NIL); - - /* Record the remote data node chunk ID mappings */ - ts_chunk_data_node_insert_multi(chunk->data_nodes); - } else elog(ERROR, "invalid relkind \"%c\" when creating chunk", chunk->relkind); @@ -4455,9 +4415,6 @@ ts_chunk_drop_chunks(PG_FUNCTION_ARGS) MemoryContextSwitchTo(oldcontext); - if (data_node_oids != NIL) - ts_cm_functions->func_call_on_data_nodes(fcinfo, data_node_oids); - /* store data for multi function call */ funcctx->max_calls = list_length(dc_names); funcctx->user_fctx = dc_names; diff --git a/src/cross_module_fn.c b/src/cross_module_fn.c index 3e45848fab9..d33d74a7e61 100644 --- a/src/cross_module_fn.c +++ b/src/cross_module_fn.c @@ -89,51 +89,16 @@ CROSSMODULE_WRAPPER(invalidation_process_hypertable_log); CROSSMODULE_WRAPPER(invalidation_process_cagg_log); CROSSMODULE_WRAPPER(cagg_try_repair); -CROSSMODULE_WRAPPER(data_node_ping); -CROSSMODULE_WRAPPER(data_node_block_new_chunks); -CROSSMODULE_WRAPPER(data_node_allow_new_chunks); -CROSSMODULE_WRAPPER(data_node_add); -CROSSMODULE_WRAPPER(data_node_delete); -CROSSMODULE_WRAPPER(data_node_attach); -CROSSMODULE_WRAPPER(data_node_detach); -CROSSMODULE_WRAPPER(data_node_alter); -CROSSMODULE_WRAPPER(chunk_drop_replica); CROSSMODULE_WRAPPER(chunk_freeze_chunk); CROSSMODULE_WRAPPER(chunk_unfreeze_chunk); -CROSSMODULE_WRAPPER(chunks_drop_stale); -CROSSMODULE_WRAPPER(chunk_set_default_data_node); CROSSMODULE_WRAPPER(chunk_get_relstats); CROSSMODULE_WRAPPER(chunk_get_colstats); CROSSMODULE_WRAPPER(chunk_create_empty_table); -CROSSMODULE_WRAPPER(chunk_create_replica_table); CROSSMODULE_WRAPPER(recompress_chunk_segmentwise); CROSSMODULE_WRAPPER(get_compressed_chunk_index_for_recompression); -TS_FUNCTION_INFO_V1(ts_dist_set_id); -Datum -ts_dist_set_id(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(ts_cm_functions->set_distributed_id(PG_GETARG_DATUM(0))); -} - -TS_FUNCTION_INFO_V1(ts_dist_set_peer_id); -Datum -ts_dist_set_peer_id(PG_FUNCTION_ARGS) -{ - ts_cm_functions->set_distributed_peer_id(PG_GETARG_DATUM(0)); - PG_RETURN_VOID(); -} - -TS_FUNCTION_INFO_V1(ts_dist_validate_as_data_node); -Datum -ts_dist_validate_as_data_node(PG_FUNCTION_ARGS) -{ - ts_cm_functions->validate_as_data_node(); - PG_RETURN_VOID(); -} - /* * casting a function pointer to a pointer of another type is undefined * behavior, so we need one of these for every function type we have @@ -254,21 +219,6 @@ process_cagg_try_repair(PG_FUNCTION_ARGS) pg_unreachable(); } -static void -hypertable_make_distributed_default_fn(Hypertable *ht, List *data_node_names) -{ - error_no_default_fn_community(); -} - -static List * -get_and_validate_data_node_list_default_fn(ArrayType *nodearr) -{ - error_no_default_fn_community(); - pg_unreachable(); - - return NIL; -} - static void cache_syscache_invalidate_default(Datum arg, int cacheid, uint32 hashvalue) { @@ -315,45 +265,6 @@ continuous_agg_call_invalidation_trigger_default(int32 hypertable_id, Relation c pg_unreachable(); } -static Datum -empty_fn(PG_FUNCTION_ARGS) -{ - PG_RETURN_VOID(); -} - -static void -create_chunk_on_data_nodes_default(const Chunk *chunk, const Hypertable *ht, - const char *remote_chunk_name, List *data_nodes) -{ - error_no_default_fn_community(); -} - -static bool -set_distributed_id_default(Datum d) -{ - return error_no_default_fn_bool_void_community(); -} - -static void -set_distributed_peer_id_default(Datum d) -{ - error_no_default_fn_community(); -} - -static void -func_call_on_data_nodes_default(FunctionCallInfo finfo, List *data_node_oids) -{ - error_no_default_fn_community(); - pg_unreachable(); -} - -static void -dist_update_stale_chunk_metadata_default(Chunk *new_chunk, List *chunk_data_nodes) -{ - error_no_default_fn_community(); - pg_unreachable(); -} - TS_FUNCTION_INFO_V1(ts_tsl_loaded); PGDLLEXPORT Datum @@ -362,13 +273,6 @@ ts_tsl_loaded(PG_FUNCTION_ARGS) PG_RETURN_BOOL(ts_cm_functions != &ts_cm_functions_default); } -static void -mn_get_foreign_join_path_default_fn_pg_community(PlannerInfo *root, RelOptInfo *joinrel, - RelOptInfo *outerrel, RelOptInfo *innerrel, - JoinType jointype, JoinPathExtraData *extra) -{ -} - /* * Define cross-module functions' default values: * If the submodule isn't activated, using one of the cm functions will throw an @@ -441,9 +345,7 @@ TSDLLEXPORT CrossModuleFunctions ts_cm_functions_default = { .continuous_agg_validate_query = error_no_default_fn_pg_community, .invalidation_cagg_log_add_entry = error_no_default_fn_pg_community, .invalidation_hyper_log_add_entry = error_no_default_fn_pg_community, - .remote_invalidation_log_delete = NULL, .drop_dist_ht_invalidation_trigger = error_no_default_fn_pg_community, - .remote_drop_dist_ht_invalidation_trigger = NULL, .invalidation_process_hypertable_log = error_no_default_fn_pg_community, .invalidation_process_cagg_log = error_no_default_fn_pg_community, .cagg_try_repair = process_cagg_try_repair, @@ -468,52 +370,16 @@ TSDLLEXPORT CrossModuleFunctions ts_cm_functions_default = { .array_compressor_append = error_no_default_fn_pg_community, .array_compressor_finish = error_no_default_fn_pg_community, - .data_node_add = error_no_default_fn_pg_community, - .data_node_delete = error_no_default_fn_pg_community, - .data_node_attach = error_no_default_fn_pg_community, - .data_node_ping = error_no_default_fn_pg_community, - .data_node_detach = error_no_default_fn_pg_community, - .data_node_alter = error_no_default_fn_pg_community, - .data_node_allow_new_chunks = error_no_default_fn_pg_community, - .data_node_block_new_chunks = error_no_default_fn_pg_community, - .distributed_exec = error_no_default_fn_pg_community, - .create_distributed_restore_point = error_no_default_fn_pg_community, - .chunk_set_default_data_node = error_no_default_fn_pg_community, .show_chunk = error_no_default_fn_pg_community, .create_chunk = error_no_default_fn_pg_community, - .create_chunk_on_data_nodes = create_chunk_on_data_nodes_default, - .chunk_drop_replica = error_no_default_fn_pg_community, .chunk_freeze_chunk = error_no_default_fn_pg_community, .chunk_unfreeze_chunk = error_no_default_fn_pg_community, - .chunks_drop_stale = error_no_default_fn_pg_community, - .hypertable_make_distributed = hypertable_make_distributed_default_fn, - .get_and_validate_data_node_list = get_and_validate_data_node_list_default_fn, - .timescaledb_fdw_handler = error_no_default_fn_pg_community, - .timescaledb_fdw_validator = empty_fn, .cache_syscache_invalidate = cache_syscache_invalidate_default, - .remote_txn_id_in = error_no_default_fn_pg_community, - .remote_txn_id_out = error_no_default_fn_pg_community, - .remote_txn_heal_data_node = error_no_default_fn_pg_community, - .remote_connection_cache_show = error_no_default_fn_pg_community, - .set_distributed_id = set_distributed_id_default, - .set_distributed_peer_id = set_distributed_peer_id_default, - .is_access_node_session = error_no_default_fn_bool_void_community, - .remove_from_distributed_db = error_no_default_fn_bool_void_community, - .dist_remote_hypertable_info = error_no_default_fn_pg_community, - .dist_remote_chunk_info = error_no_default_fn_pg_community, - .dist_remote_compressed_chunk_info = error_no_default_fn_pg_community, - .dist_remote_hypertable_index_info = error_no_default_fn_pg_community, - .dist_update_stale_chunk_metadata = dist_update_stale_chunk_metadata_default, - .validate_as_data_node = error_no_default_fn_community, - .func_call_on_data_nodes = func_call_on_data_nodes_default, .chunk_get_relstats = error_no_default_fn_pg_community, .chunk_get_colstats = error_no_default_fn_pg_community, .chunk_create_empty_table = error_no_default_fn_pg_community, - .chunk_create_replica_table = error_no_default_fn_pg_community, - .hypertable_distributed_set_replication_factor = error_no_default_fn_pg_community, .recompress_chunk_segmentwise = error_no_default_fn_pg_community, .get_compressed_chunk_index_for_recompression = error_no_default_fn_pg_community, - .mn_get_foreign_join_paths = mn_get_foreign_join_path_default_fn_pg_community, }; TSDLLEXPORT CrossModuleFunctions *ts_cm_functions = &ts_cm_functions_default; diff --git a/src/cross_module_fn.h b/src/cross_module_fn.h index 26f8872a3dd..7d7eb376aa4 100644 --- a/src/cross_module_fn.h +++ b/src/cross_module_fn.h @@ -151,57 +151,17 @@ typedef struct CrossModuleFunctions PGFunction array_compressor_append; PGFunction array_compressor_finish; - PGFunction data_node_add; - PGFunction data_node_delete; - PGFunction data_node_attach; - PGFunction data_node_ping; - PGFunction data_node_detach; - PGFunction data_node_alter; - PGFunction data_node_allow_new_chunks; - PGFunction data_node_block_new_chunks; - - PGFunction chunk_set_default_data_node; PGFunction create_chunk; PGFunction show_chunk; - List *(*get_and_validate_data_node_list)(ArrayType *nodearr); - void (*hypertable_make_distributed)(Hypertable *ht, List *data_node_names); - PGFunction timescaledb_fdw_handler; - PGFunction timescaledb_fdw_validator; void (*cache_syscache_invalidate)(Datum arg, int cacheid, uint32 hashvalue); - PGFunction remote_txn_id_in; - PGFunction remote_txn_id_out; - PGFunction remote_txn_heal_data_node; - PGFunction remote_connection_cache_show; - void (*create_chunk_on_data_nodes)(const Chunk *chunk, const Hypertable *ht, - const char *remote_chunk_name, List *data_nodes); - bool (*set_distributed_id)(Datum id); - void (*set_distributed_peer_id)(Datum id); - bool (*is_access_node_session)(void); - bool (*remove_from_distributed_db)(void); - PGFunction dist_remote_hypertable_info; - PGFunction dist_remote_chunk_info; - PGFunction dist_remote_compressed_chunk_info; - PGFunction dist_remote_hypertable_index_info; - void (*dist_update_stale_chunk_metadata)(Chunk *new_chunk, List *chunk_data_nodes); - void (*validate_as_data_node)(void); - void (*func_call_on_data_nodes)(FunctionCallInfo fcinfo, List *data_node_oids); - PGFunction distributed_exec; - PGFunction create_distributed_restore_point; PGFunction chunk_get_relstats; PGFunction chunk_get_colstats; - PGFunction hypertable_distributed_set_replication_factor; PGFunction chunk_create_empty_table; - PGFunction chunk_create_replica_table; - PGFunction chunk_drop_replica; PGFunction chunk_freeze_chunk; PGFunction chunk_unfreeze_chunk; - PGFunction chunks_drop_stale; PGFunction recompress_chunk_segmentwise; PGFunction get_compressed_chunk_index_for_recompression; - void (*mn_get_foreign_join_paths)(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, - RelOptInfo *innerrel, JoinType jointype, - JoinPathExtraData *extra); } CrossModuleFunctions; extern TSDLLEXPORT CrossModuleFunctions *ts_cm_functions; diff --git a/src/dimension.c b/src/dimension.c index c09cd99f62f..f2d1a1b3a21 100644 --- a/src/dimension.c +++ b/src/dimension.c @@ -1279,7 +1279,6 @@ ts_dimension_set_num_slices(PG_FUNCTION_ARGS) */ num_slices = num_slices_arg & 0xffff; ts_dimension_update(ht, colname, DIMENSION_TYPE_CLOSED, NULL, NULL, &num_slices, NULL); - ts_hypertable_func_call_on_data_nodes(ht, fcinfo); ts_cache_release(hcache); PG_RETURN_VOID(); @@ -1324,7 +1323,6 @@ ts_dimension_set_interval(PG_FUNCTION_ARGS) intervaltype = get_fn_expr_argtype(fcinfo->flinfo, 1); ts_dimension_update(ht, colname, DIMENSION_TYPE_OPEN, &interval, &intervaltype, NULL, NULL); - ts_hypertable_func_call_on_data_nodes(ht, fcinfo); ts_cache_release(hcache); PG_RETURN_VOID(); @@ -1696,8 +1694,6 @@ ts_dimension_add_internal(FunctionCallInfo fcinfo, DimensionInfo *info, bool is_ } } - ts_hypertable_func_call_on_data_nodes(info->ht, fcinfo); - retval = dimension_create_datum(fcinfo, info, is_generic); ts_cache_release(hcache); diff --git a/src/hypertable.c b/src/hypertable.c index 67b28531d31..236a9372ea8 100644 --- a/src/hypertable.c +++ b/src/hypertable.c @@ -1569,109 +1569,6 @@ ts_validate_replication_factor(const char *hypertable_name, int32 replication_fa return (int16) (replication_factor & 0xFFFF); } -static int16 -hypertable_validate_create_call(const char *hypertable_name, bool distributed, - bool distributed_is_null, int32 replication_factor, - bool replication_factor_is_null, ArrayType *data_node_arr, - List **data_nodes) -{ - bool distributed_local_error = false; - - if (!distributed_is_null && !replication_factor_is_null) - { - /* create_hypertable(distributed, replication_factor) */ - if (!distributed) - distributed_local_error = true; - } - else if (!distributed_is_null) - { - /* create_hypertable(distributed) */ - switch (ts_guc_hypertable_distributed_default) - { - case HYPERTABLE_DIST_AUTO: - case HYPERTABLE_DIST_DISTRIBUTED: - if (distributed) - replication_factor = ts_guc_hypertable_replication_factor_default; - else - { - /* creating regular hypertable according to the policy */ - } - break; - case HYPERTABLE_DIST_LOCAL: - if (distributed) - replication_factor = ts_guc_hypertable_replication_factor_default; - else - distributed_local_error = true; - break; - } - } - else if (!replication_factor_is_null) - { - /* create_hypertable(replication_factor) */ - switch (ts_guc_hypertable_distributed_default) - { - case HYPERTABLE_DIST_AUTO: - case HYPERTABLE_DIST_DISTRIBUTED: - /* distributed and distributed member */ - distributed = true; - break; - case HYPERTABLE_DIST_LOCAL: - distributed_local_error = true; - break; - } - } - else - { - /* create_hypertable() */ - switch (ts_guc_hypertable_distributed_default) - { - case HYPERTABLE_DIST_AUTO: - distributed = false; - break; - case HYPERTABLE_DIST_LOCAL: - distributed_local_error = true; - break; - case HYPERTABLE_DIST_DISTRIBUTED: - replication_factor = ts_guc_hypertable_replication_factor_default; - distributed = true; - break; - } - } - - if (distributed_local_error) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("local hypertables cannot set replication_factor"), - errhint("Set distributed=>true or use create_distributed_hypertable() to create a " - "distributed hypertable."))); - - if (!distributed) - return 0; - - /* - * Special replication_factor case for hypertables created on remote - * data nodes. Used to distinguish them from regular hypertables. - * - * Such argument is only allowed to be use by access node session. - */ - if (replication_factor == -1) - { - bool an_session_on_dn = - ts_cm_functions->is_access_node_session && ts_cm_functions->is_access_node_session(); - if (an_session_on_dn) - return -1; - } - - /* Validate data nodes and check permissions on them */ - if (replication_factor > 0) - *data_nodes = ts_cm_functions->get_and_validate_data_node_list(data_node_arr); - - /* Check replication_factor value and the number of nodes */ - return ts_validate_replication_factor(hypertable_name, - replication_factor, - list_length(*data_nodes)); -} - TS_FUNCTION_INFO_V1(ts_hypertable_create); TS_FUNCTION_INFO_V1(ts_hypertable_distributed_create); TS_FUNCTION_INFO_V1(ts_hypertable_create_general); @@ -1746,13 +1643,7 @@ ts_hypertable_create_internal(FunctionCallInfo fcinfo, Oid table_relid, * Validate data nodes and check permissions on them if this is a * distributed hypertable. */ - replication_factor = hypertable_validate_create_call(get_rel_name(table_relid), - distributed, - distributed_is_null, - replication_factor_in, - replication_factor_is_null, - data_node_arr, - &data_nodes); + replication_factor = 0; if (closed_dim_info && !closed_dim_info->num_slices_is_set) { @@ -2280,15 +2171,6 @@ ts_hypertable_create_from_info(Oid table_relid, int32 hypertable_id, uint32 flag if ((flags & HYPERTABLE_CREATE_DISABLE_DEFAULT_INDEXES) == 0) ts_indexing_create_default_indexes(ht); - if (replication_factor > 0) - ts_cm_functions->hypertable_make_distributed(ht, data_node_names); - else if (list_length(data_node_names) > 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid replication factor"), - errhint("The replication factor should be 1 or greater with a non-empty data node " - "list."))); - ts_cache_release(hcache); return true; @@ -2479,7 +2361,6 @@ ts_hypertable_set_integer_now_func(PG_FUNCTION_ARGS) NULL, NULL, &now_func_oid); - ts_hypertable_func_call_on_data_nodes(hypertable, fcinfo); ts_cache_release(hcache); PG_RETURN_NULL(); } @@ -2849,13 +2730,6 @@ ts_hypertable_get_type(const Hypertable *ht) return HYPERTABLE_DISTRIBUTED; } -void -ts_hypertable_func_call_on_data_nodes(const Hypertable *ht, FunctionCallInfo fcinfo) -{ - if (hypertable_is_distributed(ht)) - ts_cm_functions->func_call_on_data_nodes(fcinfo, ts_hypertable_get_data_node_name_list(ht)); -} - /* * Get the max value of an open dimension. */ diff --git a/src/hypertable.h b/src/hypertable.h index fc63271e1ef..95481e227ec 100644 --- a/src/hypertable.h +++ b/src/hypertable.h @@ -171,8 +171,6 @@ extern TSDLLEXPORT List *ts_hypertable_get_available_data_node_names(const Hyper bool error_if_missing); extern TSDLLEXPORT List *ts_hypertable_get_available_data_node_server_oids(const Hypertable *ht); extern TSDLLEXPORT HypertableType ts_hypertable_get_type(const Hypertable *ht); -extern TSDLLEXPORT void ts_hypertable_func_call_on_data_nodes(const Hypertable *ht, - FunctionCallInfo fcinfo); extern TSDLLEXPORT int64 ts_hypertable_get_open_dim_max_value(const Hypertable *ht, int dimension_index, bool *isnull); diff --git a/src/nodes/chunk_dispatch/chunk_dispatch.c b/src/nodes/chunk_dispatch/chunk_dispatch.c index 1bdc93da855..915774585f9 100644 --- a/src/nodes/chunk_dispatch/chunk_dispatch.c +++ b/src/nodes/chunk_dispatch/chunk_dispatch.c @@ -141,24 +141,6 @@ ts_chunk_dispatch_get_chunk_insert_state(ChunkDispatch *dispatch, Point *point, if (!chunk) elog(ERROR, "no chunk found or created"); - /* get the filtered list of "available" DNs for this chunk but only if it's replicated */ - if (found && dispatch->hypertable->fd.replication_factor > 1) - { - List *chunk_data_nodes = - ts_chunk_data_node_scan_by_chunk_id_filter(chunk->fd.id, CurrentMemoryContext); - - /* - * If the chunk was not created as part of this insert, we need to check whether any - * of the chunk's data nodes are currently unavailable and in that case consider the - * chunk stale on those data nodes. Do that by removing the AN's chunk-datanode - * mapping for the unavailable data nodes. - */ - if (dispatch->hypertable->fd.replication_factor > list_length(chunk_data_nodes)) - ts_cm_functions->dist_update_stale_chunk_metadata(chunk, chunk_data_nodes); - - list_free(chunk_data_nodes); - } - cis = ts_chunk_insert_state_create(chunk, dispatch); /* diff --git a/src/planner/planner.c b/src/planner/planner.c index 1f4e6484ee0..e72c6f2d61e 100644 --- a/src/planner/planner.c +++ b/src/planner/planner.c @@ -109,7 +109,6 @@ void _planner_fini(void); static planner_hook_type prev_planner_hook; static set_rel_pathlist_hook_type prev_set_rel_pathlist_hook; -static set_join_pathlist_hook_type prev_set_join_pathlist_hook; static get_relation_info_hook_type prev_get_relation_info_hook; static create_upper_paths_hook_type prev_create_upper_paths_hook; static void cagg_reorder_groupby_clause(RangeTblEntry *subq_rte, Index rtno, List *outer_sortcl, @@ -1737,36 +1736,13 @@ cagg_reorder_groupby_clause(RangeTblEntry *subq_rte, Index rtno, List *outer_sor } } -/* Register our join pushdown hook. Becuase for PostgreSQL the tables we are operating - * on are local tables. So, the FDW hooks are not called. Register our join path - * generation as a generic planer hook. - */ - -static void -timescaledb_set_join_pathlist_hook(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, - RelOptInfo *innerrel, JoinType jointype, - JoinPathExtraData *extra) -{ - /* Left table has to be a distributed hypertable */ - TimescaleDBPrivate *outerrel_private = outerrel->fdw_private; - if (outerrel_private != NULL && outerrel_private->fdw_relation_info != NULL) - ts_cm_functions - ->mn_get_foreign_join_paths(root, joinrel, outerrel, innerrel, jointype, extra); - - /* Call next hook in chain */ - if (prev_set_join_pathlist_hook != NULL) - (*prev_set_join_pathlist_hook)(root, joinrel, outerrel, innerrel, jointype, extra); -} - void _planner_init(void) { prev_planner_hook = planner_hook; planner_hook = timescaledb_planner; prev_set_rel_pathlist_hook = set_rel_pathlist_hook; - prev_set_join_pathlist_hook = set_join_pathlist_hook; set_rel_pathlist_hook = timescaledb_set_rel_pathlist; - set_join_pathlist_hook = timescaledb_set_join_pathlist_hook; prev_get_relation_info_hook = get_relation_info_hook; get_relation_info_hook = timescaledb_get_relation_info_hook; @@ -1780,7 +1756,6 @@ _planner_fini(void) { planner_hook = prev_planner_hook; set_rel_pathlist_hook = prev_set_rel_pathlist_hook; - set_join_pathlist_hook = prev_set_join_pathlist_hook; get_relation_info_hook = prev_get_relation_info_hook; create_upper_paths_hook = prev_create_upper_paths_hook; } diff --git a/tsl/src/chunk.c b/tsl/src/chunk.c index d215a42cb2c..15af2efe402 100644 --- a/tsl/src/chunk.c +++ b/tsl/src/chunk.c @@ -46,256 +46,60 @@ #include "deparse.h" #include "debug_point.h" #include "dist_util.h" -#include "remote/dist_commands.h" #include "ts_catalog/chunk_data_node.h" #include "utils.h" -static bool -chunk_match_data_node_by_server(const Chunk *chunk, const ForeignServer *server) -{ - bool server_found = false; - ListCell *lc; - - foreach (lc, chunk->data_nodes) - { - ChunkDataNode *cdn = lfirst(lc); - - if (cdn->foreign_server_oid == server->serverid) - { - server_found = true; - break; - } - } - - return server_found; -} - -static bool -chunk_set_foreign_server(const Chunk *chunk, const ForeignServer *new_server) -{ - Relation ftrel; - HeapTuple tuple; - HeapTuple copy; - Datum values[Natts_pg_foreign_table]; - bool nulls[Natts_pg_foreign_table]; - CatalogSecurityContext sec_ctx; - Oid old_server_id; - long updated; - - if (!chunk_match_data_node_by_server(chunk, new_server)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("chunk \"%s\" does not exist on data node \"%s\"", - get_rel_name(chunk->table_id), - new_server->servername))); - - tuple = SearchSysCache1(FOREIGNTABLEREL, ObjectIdGetDatum(chunk->table_id)); - - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("chunk \"%s\" is not a foreign table", get_rel_name(chunk->table_id)))); - - ftrel = table_open(ForeignTableRelationId, RowExclusiveLock); - - heap_deform_tuple(tuple, RelationGetDescr(ftrel), values, nulls); - - old_server_id = - DatumGetObjectId(values[AttrNumberGetAttrOffset(Anum_pg_foreign_table_ftserver)]); - - if (old_server_id == new_server->serverid) - { - table_close(ftrel, RowExclusiveLock); - ReleaseSysCache(tuple); - return false; - } - - values[AttrNumberGetAttrOffset(Anum_pg_foreign_table_ftserver)] = - ObjectIdGetDatum(new_server->serverid); - - copy = heap_form_tuple(RelationGetDescr(ftrel), values, nulls); - - ts_catalog_database_info_become_owner(ts_catalog_database_info_get(), &sec_ctx); - ts_catalog_update_tid(ftrel, &tuple->t_self, copy); - ts_catalog_restore_user(&sec_ctx); - - table_close(ftrel, RowExclusiveLock); - heap_freetuple(copy); - ReleaseSysCache(tuple); - /* invalidate foreign table cache */ - CacheInvalidateRelcacheByRelid(ForeignTableRelationId); - /* update dependencies between foreign table and foreign server */ - updated = changeDependencyFor(RelationRelationId, - chunk->table_id, - ForeignServerRelationId, - old_server_id, - new_server->serverid); - if (updated != 1) - elog(ERROR, "could not update data node for chunk \"%s\"", get_rel_name(chunk->table_id)); - - /* make changes visible */ - CommandCounterIncrement(); - - return true; -} - -/* - * Change the data node used to query a chunk. - * - * Either switch "away" from using the given data node or switch to using it - * (depending on the "available" parameter). The function will only switch - * back to using the data node if it is the determined primary/default data - * node for the chunk according to the partitioning configuration. - * - * Return true if the chunk's data node was changed or no change was - * needed. Return false if a change should have been made but wasn't possible - * (due to, e.g., lack of replica chunks). +/* Data in a frozen chunk cannot be modified. So any operation + * that rewrites data for a frozen chunk will be blocked. + * Note that a frozen chunk can still be dropped. */ -bool -chunk_update_foreign_server_if_needed(const Chunk *chunk, Oid data_node_id, bool available) +Datum +chunk_freeze_chunk(PG_FUNCTION_ARGS) { - ForeignTable *foreign_table = NULL; - ForeignServer *server = NULL; - bool should_switch_data_node = false; - ListCell *lc; - - Assert(chunk->relkind == RELKIND_FOREIGN_TABLE); - foreign_table = GetForeignTable(chunk->table_id); - - /* Cannot switch to other data node if only one or none assigned */ - if (list_length(chunk->data_nodes) < 2) - return false; - - /* Nothing to do if the chunk table already has the requested data node set */ - if ((!available && data_node_id != foreign_table->serverid) || - (available && data_node_id == foreign_table->serverid)) - return true; - - if (available) - { - /* Switch to using the given data node, but only on chunks where the - * given node is the "default" according to partitioning */ - Cache *htcache = ts_hypertable_cache_pin(); - const Hypertable *ht = - ts_hypertable_cache_get_entry(htcache, chunk->hypertable_relid, CACHE_FLAG_NONE); - const Dimension *dim = hyperspace_get_closed_dimension(ht->space, 0); - - if (dim != NULL) - { - /* For space-partitioned tables, use the current partitioning - * configuration in that dimension (dimension partition) as a - * template for picking the query data node */ - const DimensionSlice *slice = - ts_hypercube_get_slice_by_dimension_id(chunk->cube, dim->fd.id); - unsigned int i; - - Assert(dim->dimension_partitions); - - for (i = 0; i < dim->dimension_partitions->num_partitions; i++) - { - const DimensionPartition *dp = dim->dimension_partitions->partitions[i]; - - /* Match the chunk with the dimension partition. Count as a - * match if the start of chunk is within the range of the - * partition. This captures both the case when the chunk - * aligns perfectly with the partition and when it is bigger - * or smaller (due to a previous partitioning change). */ - if (slice->fd.range_start >= dp->range_start && - slice->fd.range_start <= dp->range_end) - { - ListCell *lc; - - /* Use the data node for queries if it is the first - * available data node in the partition's list (i.e., the - * default choice) */ - foreach (lc, dp->data_nodes) - { - const char *node_name = lfirst(lc); - server = GetForeignServerByName(node_name, false); - - if (ts_data_node_is_available_by_server(server)) - { - should_switch_data_node = (server->serverid == data_node_id); - break; - } - } - } - } - } - else - { - /* For hypertables without a space partition, use the data node - * assignment logic to figure out whether to use the data node as - * query data node. The "default" query data node is the first in - * the list. The chunk assign logic only returns available data - * nodes. */ - List *datanodes = ts_hypertable_assign_chunk_data_nodes(ht, chunk->cube); - const char *node_name = linitial(datanodes); - server = GetForeignServerByName(node_name, false); - - if (server->serverid == data_node_id) - should_switch_data_node = true; - } - - ts_cache_release(htcache); - } - else - { - /* Switch "away" from using the given data node. Pick the first - * "available" data node referenced by the chunk */ - foreach (lc, chunk->data_nodes) - { - const ChunkDataNode *cdn = lfirst(lc); - - if (cdn->foreign_server_oid != data_node_id) - { - server = GetForeignServer(cdn->foreign_server_oid); - - if (ts_data_node_is_available_by_server(server)) - { - should_switch_data_node = true; - break; - } - } - } - } - - if (should_switch_data_node) + Oid chunk_relid = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); + TS_PREVENT_FUNC_IF_READ_ONLY(); + Chunk *chunk = ts_chunk_get_by_relid(chunk_relid, true); + Assert(chunk != NULL); + if (chunk->relkind == RELKIND_FOREIGN_TABLE) { - Assert(server != NULL); - chunk_set_foreign_server(chunk, server); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("operation not supported on distributed chunk or foreign table \"%s\"", + get_rel_name(chunk_relid)))); } - - return should_switch_data_node; + if (ts_chunk_is_frozen(chunk)) + PG_RETURN_BOOL(true); + /* get Share lock. will wait for other concurrent transactions that are + * modifying the chunk. Does not block SELECTs on the chunk. + * Does not block other DDL on the chunk table. + */ + DEBUG_WAITPOINT("freeze_chunk_before_lock"); + LockRelationOid(chunk_relid, ShareLock); + bool ret = ts_chunk_set_frozen(chunk); + PG_RETURN_BOOL(ret); } Datum -chunk_set_default_data_node(PG_FUNCTION_ARGS) +chunk_unfreeze_chunk(PG_FUNCTION_ARGS) { Oid chunk_relid = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); - const char *node_name = PG_ARGISNULL(1) ? NULL : PG_GETARG_CSTRING(1); - ForeignServer *server; - Chunk *chunk; - - if (!OidIsValid(chunk_relid)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid chunk: cannot be NULL"))); - - chunk = ts_chunk_get_by_relid(chunk_relid, false); - - if (NULL == chunk) + TS_PREVENT_FUNC_IF_READ_ONLY(); + Chunk *chunk = ts_chunk_get_by_relid(chunk_relid, true); + Assert(chunk != NULL); + if (chunk->relkind == RELKIND_FOREIGN_TABLE) + { ereport(ERROR, - (errcode(ERRCODE_TS_CHUNK_NOT_EXIST), - errmsg("relation \"%s\" is not a chunk", get_rel_name(chunk_relid)))); - - ts_hypertable_permissions_check(chunk->hypertable_relid, GetUserId()); - - server = data_node_get_foreign_server(node_name, ACL_USAGE, true, false); - - Assert(NULL != server); - - PG_RETURN_BOOL(chunk_set_foreign_server(chunk, server)); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("operation not supported on distributed chunk or foreign table \"%s\"", + get_rel_name(chunk_relid)))); + } + if (!ts_chunk_is_frozen(chunk)) + PG_RETURN_BOOL(true); + /* This is a previously frozen chunk. Only selects are permitted on this chunk. + * This changes the status in the catalog to allow previously blocked operations. + */ + bool ret = ts_chunk_unset_frozen(chunk); + PG_RETURN_BOOL(ret); } /* @@ -388,465 +192,3 @@ chunk_invoke_drop_chunks(Oid relid, Datum older_than, Datum older_than_type, boo return num_results; } - -static bool -chunk_is_distributed(const Chunk *chunk) -{ - return chunk->relkind == RELKIND_FOREIGN_TABLE; -} - -Datum -chunk_create_replica_table(PG_FUNCTION_ARGS) -{ - Oid chunk_relid; - const char *data_node_name; - const Chunk *chunk; - const Hypertable *ht; - const ForeignServer *server; - Cache *hcache = ts_hypertable_cache_pin(); - - TS_PREVENT_FUNC_IF_READ_ONLY(); - - GETARG_NOTNULL_OID(chunk_relid, 0, "chunk"); - GETARG_NOTNULL_NULLABLE(data_node_name, 1, "data node name", CSTRING); - - chunk = ts_chunk_get_by_relid(chunk_relid, false); - if (chunk == NULL) - { - const char *rel_name = get_rel_name(chunk_relid); - if (rel_name == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("oid \"%u\" is not a chunk", chunk_relid))); - else - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("relation \"%s\" is not a chunk", rel_name))); - } - if (!chunk_is_distributed(chunk)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("chunk \"%s\" doesn't belong to a distributed hypertable", - get_rel_name(chunk_relid)))); - - ht = ts_hypertable_cache_get_entry(hcache, chunk->hypertable_relid, CACHE_FLAG_NONE); - ts_hypertable_permissions_check(ht->main_table_relid, GetUserId()); - - /* Check the given data node exists */ - server = data_node_get_foreign_server(data_node_name, ACL_USAGE, true, false); - /* Find if hypertable is attached to the data node and return an error otherwise */ - data_node_hypertable_get_by_node_name(ht, data_node_name, true); - - if (chunk_match_data_node_by_server(chunk, server)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("chunk \"%s\" already exists on data node \"%s\"", - get_rel_name(chunk_relid), - data_node_name))); - - chunk_api_call_create_empty_chunk_table(ht, chunk, data_node_name); - - ts_cache_release(hcache); - - PG_RETURN_VOID(); -} - -/* - * chunk_drop_replica: - * - * This function drops a chunk on a specified data node. It then - * removes the metadata about the association of the chunk to this - * data node on the access node. - */ -Datum -chunk_drop_replica(PG_FUNCTION_ARGS) -{ - Oid chunk_relid = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); - const char *node_name = PG_ARGISNULL(1) ? NULL : NameStr(*PG_GETARG_NAME(1)); - ForeignServer *server; - Chunk *chunk; - - TS_PREVENT_FUNC_IF_READ_ONLY(); - - if (!OidIsValid(chunk_relid)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid chunk relation"))); - - chunk = ts_chunk_get_by_relid(chunk_relid, false); - - if (NULL == chunk) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid chunk relation"), - errdetail("Object with OID %u is not a chunk relation", chunk_relid))); - - /* It has to be a foreign table chunk */ - if (chunk->relkind != RELKIND_FOREIGN_TABLE) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("\"%s\" is not a valid remote chunk", get_rel_name(chunk_relid)))); - - server = data_node_get_foreign_server(node_name, ACL_USAGE, true, false); - Assert(NULL != server); - - /* Early abort on missing permissions */ - ts_hypertable_permissions_check(chunk_relid, GetUserId()); - - if (!ts_chunk_has_data_node(chunk, node_name)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("chunk \"%s\" does not exist on data node \"%s\"", - get_rel_name(chunk_relid), - node_name))); - - /* - * There should be at least one surviving replica after the deletion here. - * - * We could fetch the corresponding hypertable and check its - * replication_factor. But the user of this function is using it - * to move chunk from one data node to another and is well aware of - * the replication_factor requirements - */ - if (list_length(chunk->data_nodes) <= 1) - ereport(ERROR, - (errcode(ERRCODE_TS_INSUFFICIENT_NUM_DATA_NODES), - errmsg("cannot drop the last chunk replica"), - errdetail("Dropping the last chunk replica could lead to data loss."))); - - chunk_api_call_chunk_drop_replica(chunk, node_name, server->serverid); - - PG_RETURN_VOID(); -} - -/* Data in a frozen chunk cannot be modified. So any operation - * that rewrites data for a frozen chunk will be blocked. - * Note that a frozen chunk can still be dropped. - */ -Datum -chunk_freeze_chunk(PG_FUNCTION_ARGS) -{ - Oid chunk_relid = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); - TS_PREVENT_FUNC_IF_READ_ONLY(); - Chunk *chunk = ts_chunk_get_by_relid(chunk_relid, true); - Assert(chunk != NULL); - if (chunk->relkind == RELKIND_FOREIGN_TABLE) - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("operation not supported on distributed chunk or foreign table \"%s\"", - get_rel_name(chunk_relid)))); - } - if (ts_chunk_is_frozen(chunk)) - PG_RETURN_BOOL(true); - /* get Share lock. will wait for other concurrent transactions that are - * modifying the chunk. Does not block SELECTs on the chunk. - * Does not block other DDL on the chunk table. - */ - DEBUG_WAITPOINT("freeze_chunk_before_lock"); - LockRelationOid(chunk_relid, ShareLock); - bool ret = ts_chunk_set_frozen(chunk); - PG_RETURN_BOOL(ret); -} - -Datum -chunk_unfreeze_chunk(PG_FUNCTION_ARGS) -{ - Oid chunk_relid = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); - TS_PREVENT_FUNC_IF_READ_ONLY(); - Chunk *chunk = ts_chunk_get_by_relid(chunk_relid, true); - Assert(chunk != NULL); - if (chunk->relkind == RELKIND_FOREIGN_TABLE) - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("operation not supported on distributed chunk or foreign table \"%s\"", - get_rel_name(chunk_relid)))); - } - if (!ts_chunk_is_frozen(chunk)) - PG_RETURN_BOOL(true); - /* This is a previously frozen chunk. Only selects are permitted on this chunk. - * This changes the status in the catalog to allow previously blocked operations. - */ - bool ret = ts_chunk_unset_frozen(chunk); - PG_RETURN_BOOL(ret); -} - -static List * -chunk_id_list_create(ArrayType *array) -{ - /* create a sorted list of chunk ids from array */ - ArrayIterator it; - Datum id_datum; - List *id_list = NIL; - bool isnull; - - it = array_create_iterator(array, 0, NULL); - while (array_iterate(it, &id_datum, &isnull)) - { - if (isnull) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("chunks array arguments cannot be NULL"))); - id_list = lappend_int(id_list, DatumGetInt32(id_datum)); - } - array_free_iterator(it); - - list_sort(id_list, list_int_cmp_compat); - return id_list; -} - -static List * -chunk_id_list_exclusive_right_merge_join(const List *an_list, const List *dn_list) -{ - /* - * merge join two sorted list and return only values which exclusively - * exists in the right target (dn_list list) - */ - List *result = NIL; - const ListCell *l = list_head(an_list); - const ListCell *r = list_head(dn_list); - for (;;) - { - if (l && r) - { - int compare = list_int_cmp_compat(l, r); - if (compare == 0) - { - /* l = r */ - l = lnext(an_list, l); - r = lnext(dn_list, r); - } - else if (compare < 0) - { - /* l < r */ - /* chunk exists only on the access node */ - l = lnext(an_list, l); - } - else - { - /* l > r */ - /* chunk exists only on the data node */ - result = lappend_int(result, lfirst_int(r)); - r = lnext(dn_list, r); - } - } - else if (l) - { - /* chunk exists only on the access node */ - l = lnext(an_list, l); - } - else if (r) - { - /* chunk exists only on the data node */ - result = lappend_int(result, lfirst_int(r)); - r = lnext(dn_list, r); - } - else - { - break; - } - } - return result; -} - -/* - * chunk_drop_stale_chunks: - * - * This function drops chunks on a specified data node if those chunks are - * not known by the access node (chunks array). - * - * This function is intended to be used on the access node and data node. - */ -void -ts_chunk_drop_stale_chunks(const char *node_name, ArrayType *chunks_array) -{ - DistUtilMembershipStatus membership; - - /* execute according to the node membership */ - membership = dist_util_membership(); - if (membership == DIST_MEMBER_ACCESS_NODE) - { - StringInfo cmd = makeStringInfo(); - bool first = true; - - if (node_name == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("node_name argument cannot be NULL"))); - if (chunks_array != NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("chunks argument cannot be used on the access node"))); - - /* get an exclusive lock on the chunks catalog table to prevent new chunk - * creation during this operation */ - LockRelationOid(ts_catalog_get()->tables[CHUNK].id, AccessExclusiveLock); - - /* generate query to execute drop_stale_chunks() on the data node */ - appendStringInfo(cmd, "SELECT _timescaledb_functions.drop_stale_chunks(NULL, array["); - - /* scan for chunks that reference the given data node */ - ScanIterator it = ts_chunk_data_nodes_scan_iterator_create(CurrentMemoryContext); - ts_chunk_data_nodes_scan_iterator_set_node_name(&it, node_name); - ts_scanner_foreach(&it) - { - TupleTableSlot *slot = ts_scan_iterator_slot(&it); - bool PG_USED_FOR_ASSERTS_ONLY isnull = false; - int32 node_chunk_id; - - node_chunk_id = - DatumGetInt32(slot_getattr(slot, Anum_chunk_data_node_node_chunk_id, &isnull)); - Assert(!isnull); - - appendStringInfo(cmd, "%s%d", first ? "" : ",", node_chunk_id); - first = false; - } - ts_scan_iterator_close(&it); - - appendStringInfo(cmd, "]::integer[])"); - - /* execute command on the data node */ - ts_dist_cmd_run_on_data_nodes(cmd->data, list_make1((char *) node_name), true); - } - else if (membership == DIST_MEMBER_DATA_NODE) - { - List *an_chunk_id_list = NIL; - List *dn_chunk_id_list = NIL; - List *dn_chunk_id_list_stale = NIL; - ListCell *lc; - Cache *htcache; - - if (node_name != NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("node_name argument cannot be used on the data node"))); - - if (chunks_array == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("chunks argument cannot be NULL"))); - - /* get a sorted list of chunk ids from the supplied chunks id argument array */ - an_chunk_id_list = chunk_id_list_create(chunks_array); - - /* get a local sorted list of chunk ids */ - dn_chunk_id_list = ts_chunk_get_all_chunk_ids(RowExclusiveLock); - - /* merge join two sorted list and get chunk ids which exists locally */ - dn_chunk_id_list_stale = - chunk_id_list_exclusive_right_merge_join(an_chunk_id_list, dn_chunk_id_list); - - /* drop stale chunks */ - htcache = ts_hypertable_cache_pin(); - foreach (lc, dn_chunk_id_list_stale) - { - const Chunk *chunk = ts_chunk_get_by_id(lfirst_int(lc), false); - Hypertable *ht; - - /* chunk might be already dropped by previous drop, if the chunk was compressed */ - if (chunk == NULL) - continue; - - /* ensure that we drop only chunks related to distributed hypertables */ - ht = ts_hypertable_cache_get_entry(htcache, chunk->hypertable_relid, CACHE_FLAG_NONE); - if (hypertable_is_distributed_member(ht)) - ts_chunk_drop(chunk, DROP_RESTRICT, DEBUG1); - } - ts_cache_release(htcache); - } - else - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("current server is not an access node or data node"))); - } -} - -Datum -chunk_drop_stale_chunks(PG_FUNCTION_ARGS) -{ - char *node_name = PG_ARGISNULL(0) ? NULL : NameStr(*PG_GETARG_NAME(0)); - ArrayType *chunks_array = PG_ARGISNULL(1) ? NULL : PG_GETARG_ARRAYTYPE_P(1); - - TS_PREVENT_FUNC_IF_READ_ONLY(); - - ts_chunk_drop_stale_chunks(node_name, chunks_array); - PG_RETURN_VOID(); -} -/* - * Update and refresh the DN list for a given chunk. We remove metadata for this chunk - * for unavailable DNs - */ -void -chunk_update_stale_metadata(Chunk *new_chunk, List *chunk_data_nodes) -{ - List *serveroids = NIL, *removeoids = NIL; - bool locked = false; - ChunkDataNode *cdn; - ListCell *lc; - - /* check that at least one data node is available for this chunk on the AN */ - if (chunk_data_nodes == NIL) - ereport(ERROR, - (errcode(ERRCODE_TS_INSUFFICIENT_NUM_DATA_NODES), - (errmsg("insufficient number of available data nodes"), - errhint("Increase the number of available data nodes on hypertable " - "\"%s\".", - get_rel_name(new_chunk->hypertable_relid))))); - - foreach (lc, chunk_data_nodes) - { - cdn = lfirst(lc); - serveroids = lappend_oid(serveroids, cdn->foreign_server_oid); - } - - foreach (lc, new_chunk->data_nodes) - { - cdn = lfirst(lc); - - /* - * check if this DN is a part of chunk_data_nodes. If not - * found in chunk_data_nodes, then we need to remove this - * chunk id to node name mapping and also update the primary - * foreign server if necessary. It's possible that this metadata - * might have been already cleared earlier in which case the - * data_nodes list for the chunk will be the same as the - * "serveroids" list and no unnecesary metadata update function - * calls will occur. - */ - if (!list_member_oid(serveroids, cdn->foreign_server_oid)) - { - if (!locked) - { - LockRelationOid(ts_catalog_get()->tables[CHUNK_DATA_NODE].id, - ShareUpdateExclusiveLock); - locked = true; - } - - chunk_update_foreign_server_if_needed(new_chunk, cdn->foreign_server_oid, false); - ts_chunk_data_node_delete_by_chunk_id_and_node_name(cdn->fd.chunk_id, - NameStr(cdn->fd.node_name)); - - removeoids = lappend_oid(removeoids, cdn->foreign_server_oid); - } - } - - /* remove entries from new_chunk->data_nodes matching removeoids */ - foreach (lc, removeoids) - { - ListCell *l; - Oid serveroid = lfirst_oid(lc); - - /* this contrived code to ensure PG12+ compatible in-place list delete */ - foreach (l, new_chunk->data_nodes) - { - cdn = lfirst(l); - - if (cdn->foreign_server_oid == serveroid) - { - new_chunk->data_nodes = list_delete_ptr(new_chunk->data_nodes, cdn); - break; - } - } - } -} diff --git a/tsl/src/chunk.h b/tsl/src/chunk.h index 8a6891aa168..12d89bb0f56 100644 --- a/tsl/src/chunk.h +++ b/tsl/src/chunk.h @@ -9,15 +9,7 @@ #include #include -extern bool chunk_update_foreign_server_if_needed(const Chunk *chunk, Oid data_node_id, - bool available); -extern Datum chunk_set_default_data_node(PG_FUNCTION_ARGS); -extern Datum chunk_drop_replica(PG_FUNCTION_ARGS); extern Datum chunk_freeze_chunk(PG_FUNCTION_ARGS); extern Datum chunk_unfreeze_chunk(PG_FUNCTION_ARGS); -extern Datum chunk_drop_stale_chunks(PG_FUNCTION_ARGS); -extern void ts_chunk_drop_stale_chunks(const char *node_name, ArrayType *chunks_array); extern int chunk_invoke_drop_chunks(Oid relid, Datum older_than, Datum older_than_type, bool use_creation_time); -extern Datum chunk_create_replica_table(PG_FUNCTION_ARGS); -extern void chunk_update_stale_metadata(Chunk *new_chunk, List *chunk_data_nodes); diff --git a/tsl/src/chunk_api.c b/tsl/src/chunk_api.c index 438ac391569..246cfd919ad 100644 --- a/tsl/src/chunk_api.c +++ b/tsl/src/chunk_api.c @@ -39,11 +39,6 @@ #include "utils.h" #include "deparse.h" -#include "remote/async.h" -#include "remote/dist_txn.h" -#include "remote/stmt_params.h" -#include "remote/dist_commands.h" -#include "remote/tuplefactory.h" #include "ts_catalog/array_utils.h" #include "ts_catalog/catalog.h" #include "ts_catalog/chunk_data_node.h" @@ -404,151 +399,6 @@ chunk_create(PG_FUNCTION_ARGS) #define ESTIMATE_JSON_STR_SIZE(num_dims) (60 * (num_dims)) -static Oid create_chunk_argtypes[CREATE_CHUNK_NUM_ARGS] = { - REGCLASSOID, JSONBOID, NAMEOID, NAMEOID, REGCLASSOID -}; - -/* - * Fill in / get the TupleDesc for the result type of the create_chunk() - * function. - */ -static void -get_create_chunk_result_type(TupleDesc *tupdesc) -{ - Oid funcoid = ts_get_function_oid(CREATE_CHUNK_FUNCTION_NAME, - FUNCTIONS_SCHEMA_NAME, - CREATE_CHUNK_NUM_ARGS, - create_chunk_argtypes); - - if (get_func_result_type(funcoid, NULL, tupdesc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("function returning record called in context " - "that cannot accept type record"))); -} - -static void -get_result_datums(Datum *values, bool *nulls, unsigned int numvals, AttInMetadata *attinmeta, - PGresult *res) -{ - unsigned int i; - - memset(nulls, 0, sizeof(bool) * numvals); - - for (i = 0; i < numvals; i++) - { - if (PQgetisnull(res, 0, i)) - nulls[i] = true; - else - values[i] = InputFunctionCall(&attinmeta->attinfuncs[i], - PQgetvalue(res, 0, i), - attinmeta->attioparams[i], - attinmeta->atttypmods[i]); - } -} - -static const char * -chunk_api_dimension_slices_json(const Chunk *chunk, const Hypertable *ht) -{ - JsonbParseState *ps = NULL; - JsonbValue *jv = hypercube_to_jsonb_value(chunk->cube, ht->space, &ps); - Jsonb *hcjson = JsonbValueToJsonb(jv); - - return JsonbToCString(NULL, &hcjson->root, ESTIMATE_JSON_STR_SIZE(ht->space->num_dimensions)); -} - -/* - * Create a replica of a chunk on all its assigned or specified list of data nodes. - * - * If "data_nodes" list is explicitly specified use that instead of the list of - * data nodes from the chunk. - */ -void -chunk_api_create_on_data_nodes(const Chunk *chunk, const Hypertable *ht, - const char *remote_chunk_name, List *data_nodes) -{ - AsyncRequestSet *reqset = async_request_set_create(); - const char *params[CREATE_CHUNK_NUM_ARGS] = { - quote_qualified_identifier(NameStr(ht->fd.schema_name), NameStr(ht->fd.table_name)), - chunk_api_dimension_slices_json(chunk, ht), - NameStr(chunk->fd.schema_name), - NameStr(chunk->fd.table_name), - remote_chunk_name ? remote_chunk_name : NULL, - }; - AsyncResponseResult *res; - ListCell *lc; - TupleDesc tupdesc; - AttInMetadata *attinmeta; - - /* - * In case of "unavailable" datanodes, the chunk->data_nodes list is already pruned - * and doesn't contain "unavailable" datanodes. So this chunk creation will never - * happen on such "unavailable" datanodes. By the same logic, metadata update on the - * AN for the chunk->datanode mappings will only happen for the listed "live" DNs - * and not for the "unavailable" ones - */ - List *target_data_nodes = data_nodes ? data_nodes : chunk->data_nodes; - - get_create_chunk_result_type(&tupdesc); - attinmeta = TupleDescGetAttInMetadata(tupdesc); - - foreach (lc, target_data_nodes) - { - ChunkDataNode *cdn = lfirst(lc); - TSConnectionId id = remote_connection_id(cdn->foreign_server_oid, GetUserId()); - TSConnection *conn = remote_dist_txn_get_connection(id, REMOTE_TXN_NO_PREP_STMT); - AsyncRequest *req; - - req = async_request_send_with_params(conn, - CHUNK_CREATE_STMT, - stmt_params_create_from_values(params, - CREATE_CHUNK_NUM_ARGS), - FORMAT_TEXT); - - async_request_attach_user_data(req, cdn); - async_request_set_add(reqset, req); - } - - while ((res = async_request_set_wait_ok_result(reqset)) != NULL) - { - PGresult *pgres = async_response_result_get_pg_result(res); - ChunkDataNode *cdn = async_response_result_get_user_data(res); - Datum values[Natts_create_chunk]; - bool nulls[Natts_create_chunk]; - const char *schema_name, *table_name; - bool created; - - Assert(Natts_create_chunk == tupdesc->natts); - get_result_datums(values, nulls, tupdesc->natts, attinmeta, pgres); - - created = DatumGetBool(values[AttrNumberGetAttrOffset(Anum_create_chunk_created)]); - - /* - * Sanity check the result. Use error rather than an assert since this - * is the result of a remote call to a data node that could potentially - * run a different version of the remote function than we'd expect. - */ - if (!created) - elog(ERROR, "chunk creation failed on data node \"%s\"", NameStr(cdn->fd.node_name)); - - if (nulls[AttrNumberGetAttrOffset(Anum_create_chunk_id)] || - nulls[AttrNumberGetAttrOffset(Anum_create_chunk_schema_name)] || - nulls[AttrNumberGetAttrOffset(Anum_create_chunk_table_name)]) - elog(ERROR, "unexpected chunk creation result on data node"); - - schema_name = - DatumGetCString(values[AttrNumberGetAttrOffset(Anum_create_chunk_schema_name)]); - table_name = DatumGetCString(values[AttrNumberGetAttrOffset(Anum_create_chunk_table_name)]); - - if (namestrcmp((Name) &chunk->fd.schema_name, schema_name) != 0 || - namestrcmp((Name) &chunk->fd.table_name, table_name) != 0) - elog(ERROR, "remote chunk has mismatching schema or table name"); - - cdn->fd.node_chunk_id = - DatumGetInt32(values[AttrNumberGetAttrOffset(Anum_create_chunk_id)]); - } -} - enum Anum_chunk_relstats { Anum_chunk_relstats_chunk_id = 1, @@ -695,43 +545,6 @@ convert_op_oid_to_strings(Oid op_id, Datum *result_strings) ReleaseSysCache(operator_tuple); } -static Oid -convert_strings_to_type_id(Datum *input_strings) -{ - Oid arg_namespace = GetSysCacheOid1(NAMESPACENAME, - Anum_pg_namespace_oid, - input_strings[ENCODED_TYPE_NAMESPACE]); - Oid result; - - Assert(OidIsValid(arg_namespace)); - result = GetSysCacheOid2(TYPENAMENSP, - Anum_pg_type_oid, - input_strings[ENCODED_TYPE_NAME], - ObjectIdGetDatum(arg_namespace)); - Assert(OidIsValid(result)); - return result; -} - -static Oid -convert_strings_to_op_id(Datum *input_strings) -{ - Oid proc_namespace = - GetSysCacheOid1(NAMESPACENAME, Anum_pg_namespace_oid, input_strings[ENCODED_OP_NAMESPACE]); - Oid larg = convert_strings_to_type_id(LargSubarrayForOpArray(input_strings)); - Oid rarg = convert_strings_to_type_id(RargSubarrayForOpArray(input_strings)); - Oid result; - - Assert(OidIsValid(proc_namespace)); - result = GetSysCacheOid4(OPERNAMENSP, - Anum_pg_operator_oid, - input_strings[ENCODED_OP_NAME], - ObjectIdGetDatum(larg), - ObjectIdGetDatum(rarg), - ObjectIdGetDatum(proc_namespace)); - Assert(OidIsValid(result)); - return result; -} - static void collect_colstat_slots(const HeapTuple tuple, const Form_pg_statistic formdata, Datum *values, bool *nulls) @@ -939,139 +752,6 @@ chunk_get_single_colstats_tuple(Chunk *chunk, int column, TupleDesc tupdesc) return heap_form_tuple(tupdesc, values, nulls); } -static void -chunk_update_colstats(Chunk *chunk, int16 attnum, float nullfract, int32 width, float distinct, - ArrayType *kind_array, ArrayType *collations, Oid *slot_ops, - ArrayType **slot_numbers, Oid *value_kinds, ArrayType **slot_values) -{ - Relation rel; - Relation sd; - Datum values[Natts_pg_statistic]; - bool nulls[Natts_pg_statistic]; - bool replaces[Natts_pg_statistic]; - HeapTuple stup; - HeapTuple oldtup; - int i, k; - int *slot_kinds; - - rel = try_relation_open(chunk->table_id, ShareUpdateExclusiveLock); - - /* If a vacuum is running we might not be able to grab the lock, so just - * raise an error and let the user try again. */ - if (NULL == rel) - ereport(ERROR, - (errcode(ERRCODE_LOCK_NOT_AVAILABLE), - errmsg("unable to acquire table lock to update column statistics on \"%s\"", - NameStr(chunk->fd.table_name)))); - - sd = relation_open(StatisticRelationId, RowExclusiveLock); - - memset(nulls, false, Natts_pg_statistic); - memset(replaces, true, Natts_pg_statistic); - - values[AttrNumberGetAttrOffset(Anum_pg_statistic_starelid)] = ObjectIdGetDatum(rel->rd_id); - values[AttrNumberGetAttrOffset(Anum_pg_statistic_staattnum)] = Int16GetDatum(attnum); - values[AttrNumberGetAttrOffset(Anum_pg_statistic_stainherit)] = BoolGetDatum(false); - values[AttrNumberGetAttrOffset(Anum_pg_statistic_stanullfrac)] = Float4GetDatum(nullfract); - values[AttrNumberGetAttrOffset(Anum_pg_statistic_stawidth)] = Int32GetDatum(width); - values[AttrNumberGetAttrOffset(Anum_pg_statistic_stadistinct)] = Float4GetDatum(distinct); - - i = AttrNumberGetAttrOffset(Anum_pg_statistic_stakind1); - slot_kinds = (int *) ARR_DATA_PTR(kind_array); - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - values[i++] = Int16GetDatum(slot_kinds[k]); /* stakindN */ - - i = AttrNumberGetAttrOffset(Anum_pg_statistic_stacoll1); - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - values[i++] = ObjectIdGetDatum(((Oid *) ARR_DATA_PTR(collations))[k]); /* stacollN */ - - i = AttrNumberGetAttrOffset(Anum_pg_statistic_staop1); - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - values[i++] = ObjectIdGetDatum(slot_ops[k]); /* staopN */ - - i = AttrNumberGetAttrOffset(Anum_pg_statistic_stanumbers1); - - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - if (slot_numbers[k] == NULL) - nulls[i++] = true; - else - values[i++] = PointerGetDatum(slot_numbers[k]); /* stanumbersN */ - - i = AttrNumberGetAttrOffset(Anum_pg_statistic_stavalues1); - - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - Oid value_oid = value_kinds[k]; - HeapTuple type_tuple; - Form_pg_type type; - int idx; - int nelems; - Datum *decoded_data; - - if (!OidIsValid(value_oid)) - { - nulls[i++] = true; - continue; - } - - type_tuple = SearchSysCache1(TYPEOID, value_oid); - Assert(HeapTupleIsValid(type_tuple)); - type = (Form_pg_type) GETSTRUCT(type_tuple); - Assert(slot_values[k] != NULL); - nelems = ts_array_length(slot_values[k]); - - decoded_data = palloc0(nelems * sizeof(Datum)); - - for (idx = 1; idx <= nelems; ++idx) - { - bool isnull; - Datum d = array_get_element(PointerGetDatum(slot_values[k]), - 1, - &idx, - CSTRING_ARY_TYPELEN, - CSTRING_TYPELEN, - CSTRING_TYPEBYVAL, - CSTRING_TYPEALIGN, - &isnull); - - Assert(!isnull); - decoded_data[idx - 1] = - OidFunctionCall3(type->typinput, d, type->typelem, type->typtypmod); - } - - values[i++] = PointerGetDatum(construct_array(decoded_data, - nelems, - value_oid, - type->typlen, - type->typbyval, - type->typalign)); - - ReleaseSysCache(type_tuple); - } - - oldtup = SearchSysCache3(STATRELATTINH, - ObjectIdGetDatum(rel->rd_id), - Int16GetDatum(attnum), - BoolGetDatum(false)); - - if (HeapTupleIsValid(oldtup)) - { - stup = heap_modify_tuple(oldtup, RelationGetDescr(sd), values, nulls, replaces); - CatalogTupleUpdate(sd, &oldtup->t_self, stup); - ReleaseSysCache(oldtup); - } - else - { - stup = heap_form_tuple(RelationGetDescr(sd), values, nulls); - CatalogTupleInsert(sd, stup); - } - - heap_freetuple(stup); - - relation_close(sd, RowExclusiveLock); - relation_close(rel, ShareUpdateExclusiveLock); -} - /* * StatsProcessContext filters out duplicate stats from replica chunks. * @@ -1098,362 +778,6 @@ typedef struct StatsProcessContext MemoryContext per_tuple_mcxt; } StatsProcessContext; -static void -stats_process_context_init(StatsProcessContext *ctx, long nstats) -{ - HASHCTL ctl; - MemSet(&ctl, 0, sizeof(ctl)); - ctl.keysize = sizeof(ChunkAttKey); - ctl.entrysize = sizeof(ChunkAttKey); - ctx->per_tuple_mcxt = - AllocSetContextCreate(CurrentMemoryContext, "Distributed ANALYZE", ALLOCSET_DEFAULT_SIZES); - ctl.hcxt = CurrentMemoryContext; - ctx->htab = - hash_create("StatsProcessContext", nstats, &ctl, HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); -} - -static bool -stats_process_context_add_chunk_attributed(StatsProcessContext *ctx, Oid relid, Index attnum) -{ - ChunkAttKey key = { - .chunk_relid = relid, - .attnum = attnum, - }; - ChunkAttKey *entry; - bool found; - - entry = hash_search(ctx->htab, &key, HASH_ENTER, &found); - - if (!found) - { - entry->chunk_relid = relid; - entry->attnum = attnum; - } - - return found; -} - -static void -stats_process_context_finish(StatsProcessContext *ctx) -{ - hash_destroy(ctx->htab); - MemoryContextDelete(ctx->per_tuple_mcxt); -} - -static void -chunk_process_remote_colstats_row(StatsProcessContext *ctx, TupleFactory *tf, TupleDesc tupdesc, - PGresult *res, int row, const char *node_name) -{ - Datum values[_Anum_chunk_colstats_max]; - bool nulls[_Anum_chunk_colstats_max] = { false }; - HeapTuple tuple; - int32 chunk_id; - ChunkDataNode *cdn; - Chunk *chunk; - int32 col_id; - float nullfract; - int32 width; - float distinct; - ArrayType *kind_array; - ArrayType *collation_array; - Datum op_strings; - Oid op_oids[STATISTIC_NUM_SLOTS]; - ArrayType *number_arrays[STATISTIC_NUM_SLOTS]; - Datum valtype_strings; - Oid valtype_oids[STATISTIC_NUM_SLOTS]; - ArrayType *value_arrays[STATISTIC_NUM_SLOTS]; - int *slot_kinds; - int i, os_idx, vt_idx; - - tuple = tuplefactory_make_tuple(tf, res, row, PQbinaryTuples(res)); - heap_deform_tuple(tuple, tupdesc, values, nulls); - chunk_id = DatumGetInt32(values[AttrNumberGetAttrOffset(Anum_chunk_relstats_chunk_id)]); - cdn = ts_chunk_data_node_scan_by_remote_chunk_id_and_node_name(chunk_id, - node_name, - CurrentMemoryContext); - chunk = ts_chunk_get_by_id(cdn->fd.chunk_id, true); - col_id = DatumGetInt32(values[AttrNumberGetAttrOffset(Anum_chunk_colstats_column_id)]); - nullfract = DatumGetFloat4(values[AttrNumberGetAttrOffset(Anum_chunk_colstats_nullfrac)]); - width = DatumGetInt32(values[AttrNumberGetAttrOffset(Anum_chunk_colstats_width)]); - distinct = DatumGetFloat4(values[AttrNumberGetAttrOffset(Anum_chunk_colstats_distinct)]); - kind_array = - DatumGetArrayTypeP(values[AttrNumberGetAttrOffset(Anum_chunk_colstats_slot_kinds)]); - collation_array = - DatumGetArrayTypeP(values[AttrNumberGetAttrOffset(Anum_chunk_colstats_slot_collations)]); - op_strings = values[AttrNumberGetAttrOffset(Anum_chunk_colstats_slot_op_strings)]; - valtype_strings = values[AttrNumberGetAttrOffset(Anum_chunk_colstats_slot_valtype_strings)]; - - slot_kinds = (int *) ARR_DATA_PTR(kind_array); - os_idx = 1; - vt_idx = 1; - - /* Filter out chunk cols we've already added. This happens when there are - * replica chunks */ - if (stats_process_context_add_chunk_attributed(ctx, chunk->table_id, col_id)) - return; - - for (i = 0; i < STATISTIC_NUM_SLOTS; ++i) - { - Datum strings[STRINGS_PER_OP_OID]; - Datum d; - int k; - - op_oids[i] = InvalidOid; - number_arrays[i] = NULL; - value_arrays[i] = NULL; - valtype_oids[i] = InvalidOid; - - /* - * As per comments in pg_statistic_d.h, "kind" codes from 0 - 99 are reserved - * for assignment by the core PostgreSQL project. Beyond that are for PostGIS - * and other projects - */ - if (!OidIsValid(slot_kinds[i]) || slot_kinds[i] > PG_STATS_KINDS_MAX) - continue; - - for (k = 0; k < STRINGS_PER_OP_OID; ++k) - { - bool isnull; - strings[k] = array_get_element(op_strings, - 1, - &os_idx, - CSTRING_ARY_TYPELEN, - CSTRING_TYPELEN, - CSTRING_TYPEBYVAL, - CSTRING_TYPEALIGN, - &isnull); - Assert(!isnull); - ++os_idx; - } - - op_oids[i] = convert_strings_to_op_id(strings); - - d = values[AttrNumberGetAttrOffset(Anum_chunk_colstats_slot1_numbers) + i]; - - if (DatumGetPointer(d) != NULL) - number_arrays[i] = DatumGetArrayTypeP(d); - - d = values[AttrNumberGetAttrOffset(Anum_chunk_colstats_slot1_values) + i]; - - if (DatumGetPointer(d) != NULL) - { - value_arrays[i] = DatumGetArrayTypeP(d); - - for (k = 0; k < STRINGS_PER_TYPE_OID; ++k) - { - bool isnull; - strings[k] = array_get_element(valtype_strings, - 1, - &vt_idx, - CSTRING_ARY_TYPELEN, - CSTRING_TYPELEN, - CSTRING_TYPEBYVAL, - CSTRING_TYPEALIGN, - &isnull); - Assert(!isnull); - ++vt_idx; - } - - valtype_oids[i] = convert_strings_to_type_id(strings); - } - } - - chunk_update_colstats(chunk, - col_id, - nullfract, - width, - distinct, - kind_array, - collation_array, - op_oids, - number_arrays, - valtype_oids, - value_arrays); -} - -/* - * Update the stats in the pg_class catalog entry for a chunk. - * - * Similar to code for vacuum/analyze. - * - * We do not update pg_class.relhasindex because vac_update_relstats() only - * sets that field if it reverts back to false (see internal implementation). - */ -static void -chunk_update_relstats(Chunk *chunk, int32 num_pages, float num_tuples, int32 num_allvisible) -{ - Relation rel; - - rel = try_relation_open(chunk->table_id, ShareUpdateExclusiveLock); - - /* If a vacuum is running we might not be able to grab the lock, so just - * raise an error and let the user try again. */ - if (NULL == rel) - ereport(ERROR, - (errcode(ERRCODE_LOCK_NOT_AVAILABLE), - errmsg("skipping relstats update of \"%s\" --- lock not available", - NameStr(chunk->fd.table_name)))); - - vac_update_relstats(rel, - num_pages, - num_tuples, - num_allvisible, - true, - InvalidTransactionId, - InvalidMultiXactId, -#if PG15_GE - NULL, - NULL, -#endif - false); - - relation_close(rel, ShareUpdateExclusiveLock); -} - -static void -chunk_process_remote_relstats_row(TupleFactory *tf, TupleDesc tupdesc, PGresult *res, int row, - const char *node_name) -{ - Datum values[_Anum_chunk_relstats_max]; - bool nulls[_Anum_chunk_relstats_max] = { false }; - HeapTuple tuple; - int32 chunk_id; - ChunkDataNode *cdn; - Chunk *chunk; - int32 num_pages; - float num_tuples; - int32 num_allvisible; - - tuple = tuplefactory_make_tuple(tf, res, row, PQbinaryTuples(res)); - heap_deform_tuple(tuple, tupdesc, values, nulls); - chunk_id = DatumGetInt32(values[AttrNumberGetAttrOffset(Anum_chunk_relstats_chunk_id)]); - cdn = ts_chunk_data_node_scan_by_remote_chunk_id_and_node_name(chunk_id, - node_name, - CurrentMemoryContext); - chunk = ts_chunk_get_by_id(cdn->fd.chunk_id, true); - num_pages = DatumGetInt32(values[AttrNumberGetAttrOffset(Anum_chunk_relstats_num_pages)]); - num_tuples = DatumGetFloat4(values[AttrNumberGetAttrOffset(Anum_chunk_relstats_num_tuples)]); - num_allvisible = - DatumGetInt32(values[AttrNumberGetAttrOffset(Anum_chunk_relstats_num_allvisible)]); - chunk_update_relstats(chunk, num_pages, num_tuples, num_allvisible); -} - -/* - * Fetch chunk relation or column stats from remote data nodes. - * - * This will remotely fetch, and locally update, relation stats (relpages, - * reltuples, relallvisible in pg_class) for all chunks in a distributed - * hypertable. - * - * For relation stats, we do not fetch 'relhasindex' because there is no way to set it - * using vac_update_relstats() unless the values reverts back to 'false' (see - * internal implementation of PG's vac_update_relstats). - * - * Note that we currently fetch stats from all chunk replicas, i.e., we might - * fetch stats for a local chunk multiple times (once for each - * replica). Presumably, stats should be the same for all replicas, but they - * might vary if ANALYZE didn't run recently on the data node. We currently - * don't care, however, and the "last" chunk replica will win w.r.t. which - * stats will take precedence. We might consider optimizing this in the - * future. - */ -static void -fetch_remote_chunk_stats(Hypertable *ht, FunctionCallInfo fcinfo, bool col_stats) -{ - StatsProcessContext statsctx; - List *data_nodes; - TupleDesc tupdesc; - TupleFactory *tf; - MemoryContext old_mcxt; - const char *sqlcmd; - AsyncRequestSet *rs; - ListCell *lc; - - Assert(hypertable_is_distributed(ht)); - - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("function returning record called in context " - "that cannot accept type record"))); - - sqlcmd = deparse_func_call(fcinfo); - rs = async_request_set_create(); - data_nodes = ts_hypertable_get_data_node_name_list(ht); - - foreach (lc, data_nodes) - { - const char *node_name = lfirst(lc); - AsyncRequest *req; - TSConnection *connection = - data_node_get_connection(node_name, REMOTE_TXN_NO_PREP_STMT, true); - req = async_request_send(connection, sqlcmd); - /* Set single-row mode in order to reduce memory usage in case result - * set is big */ - async_request_set_single_row_mode(req); - async_request_attach_user_data(req, (char *) node_name); - async_request_set_add(rs, req); - } - - tf = tuplefactory_create_for_tupdesc(tupdesc, true); - - /* Assume 500 non-duplicate stats to use for initial size of - * StatsProcessContext. Use slightly bigger than strictly necessary to - * avoid a resize. */ - stats_process_context_init(&statsctx, 500); - old_mcxt = MemoryContextSwitchTo(statsctx.per_tuple_mcxt); - - for (;;) - { - AsyncResponseResult *ar; - PGresult *res; - int ntuples; - - MemoryContextReset(statsctx.per_tuple_mcxt); - ar = async_request_set_wait_any_result(rs); - - if (NULL == ar) - break; - - res = async_response_result_get_pg_result(ar); - Assert(res != NULL); - - /* The result should be PGRES_SINGLE_TUPLE when tuples are returned - * and PGRES_TUPLES_OK when there are no new tuples to return. */ - if (PQresultStatus(res) != PGRES_SINGLE_TUPLE && PQresultStatus(res) != PGRES_TUPLES_OK) - { - TSConnectionError err; - remote_connection_get_result_error(res, &err); - async_response_result_close(ar); - remote_connection_error_elog(&err, ERROR); - } - - /* Should be in single-row mode, so either one row or none when - * done. */ - ntuples = PQntuples(res); - Assert(ntuples == 1 || ntuples == 0); - - if (ntuples == 1) - { - const char *node_name = async_response_result_get_user_data(ar); - Assert(node_name != NULL); - - if (col_stats) - chunk_process_remote_colstats_row(&statsctx, tf, tupdesc, res, 0, node_name); - else - chunk_process_remote_relstats_row(tf, tupdesc, res, 0, node_name); - } - - /* Early cleanup of PGresult protects against ballooning memory usage - * when there are a lot of rows */ - async_response_result_close(ar); - } - - MemoryContextSwitchTo(old_mcxt); - stats_process_context_finish(&statsctx); - tuplefactory_destroy(tf); -} - static void * chunk_api_generate_relstats_context(List *oids) { @@ -1557,68 +881,12 @@ chunk_api_iterate_colstats_context(FuncCallContext *funcctx) #define GET_CHUNK_RELSTATS_NAME "get_chunk_relstats" #define GET_CHUNK_COLSTATS_NAME "get_chunk_colstats" -/* - * Fetch and locally update stats for a distributed hypertable by table id. - * - * This function reconstructs the fcinfo argument of the - * chunk_api_get_chunk_stats() function in order to call - * fetch_remote_chunk_stats() and execute either - * _timescaledb_functions.get_chunk_relstats() or - * _timescaledb_functions.get_chunk_colstats() remotely (depending on the - * passed `col_stats` bool). - */ -static void -chunk_api_update_distributed_hypertable_chunk_stats(Oid table_id, bool col_stats) -{ - Cache *hcache; - Hypertable *ht; - LOCAL_FCINFO(fcinfo, 1); - FmgrInfo flinfo; - Oid funcoid; - Oid get_chunk_stats_argtypes[1] = { REGCLASSOID }; - - hcache = ts_hypertable_cache_pin(); - ht = ts_hypertable_cache_get_entry(hcache, table_id, CACHE_FLAG_NONE); - - if (!hypertable_is_distributed(ht)) - ereport(ERROR, - (errcode(ERRCODE_TS_HYPERTABLE_NOT_DISTRIBUTED), - errmsg("hypertable \"%s\" is not distributed", get_rel_name(table_id)))); - - /* Prepare fcinfo context for remote execution of _timescaledb_internal.get_chunk_relstats() */ - funcoid = ts_get_function_oid(col_stats ? GET_CHUNK_COLSTATS_NAME : GET_CHUNK_RELSTATS_NAME, - FUNCTIONS_SCHEMA_NAME, - 1, - get_chunk_stats_argtypes); - fmgr_info_cxt(funcoid, &flinfo, CurrentMemoryContext); - InitFunctionCallInfoData(*fcinfo, &flinfo, 1, InvalidOid, NULL, NULL); - FC_ARG(fcinfo, 0) = ObjectIdGetDatum(table_id); - FC_NULL(fcinfo, 0) = false; - - fetch_remote_chunk_stats(ht, fcinfo, col_stats); - - CommandCounterIncrement(); - - ts_cache_release(hcache); -} - -void -chunk_api_update_distributed_hypertable_stats(Oid table_id) -{ - /* Update stats for hypertable */ - chunk_api_update_distributed_hypertable_chunk_stats(table_id, false); - chunk_api_update_distributed_hypertable_chunk_stats(table_id, true); -} - /* * Get relation stats or column stats for chunks. * * This function takes a hypertable or chunk as input (regclass). In case of a * hypertable, it will get the relstats for all the chunks in the hypertable, * otherwise only the given chunk. - * - * If a hypertable is distributed, the function will first refresh the local - * chunk stats by fetching stats from remote data nodes. */ static Datum chunk_api_get_chunk_stats(FunctionCallInfo fcinfo, bool col_stats) @@ -1658,15 +926,6 @@ chunk_api_get_chunk_stats(FunctionCallInfo fcinfo, bool col_stats) } else { - if (hypertable_is_distributed(ht)) - { - /* If this is a distributed hypertable, we fetch stats from - * remote nodes */ - fetch_remote_chunk_stats(ht, fcinfo, col_stats); - /* Make updated stats visible so that we can retreive them locally below */ - CommandCounterIncrement(); - } - chunk_oids = find_inheritance_children(relid, NoLock); } @@ -1772,55 +1031,3 @@ chunk_create_empty_table(PG_FUNCTION_ARGS) PG_RETURN_BOOL(true); } - -#define CREATE_CHUNK_TABLE_NAME "create_chunk_table" - -void -chunk_api_call_create_empty_chunk_table(const Hypertable *ht, const Chunk *chunk, - const char *node_name) -{ - const char *create_cmd = - psprintf("SELECT %s.%s($1, $2, $3, $4)", FUNCTIONS_SCHEMA_NAME, CREATE_CHUNK_TABLE_NAME); - const char *params[4] = { quote_qualified_identifier(NameStr(ht->fd.schema_name), - NameStr(ht->fd.table_name)), - chunk_api_dimension_slices_json(chunk, ht), - NameStr(chunk->fd.schema_name), - NameStr(chunk->fd.table_name) }; - - ts_dist_cmd_close_response( - ts_dist_cmd_params_invoke_on_data_nodes(create_cmd, - stmt_params_create_from_values(params, 4), - list_make1((void *) node_name), - true)); -} - -void -chunk_api_call_chunk_drop_replica(const Chunk *chunk, const char *node_name, Oid serverid) -{ - const char *drop_cmd; - List *data_nodes; - - /* - * Drop chunk on the data node using a regular "DROP TABLE". - * Note that CASCADE is not required as it takes care of dropping compressed - * chunk (if any). - * - * If there are any other non-TimescaleDB objects attached to this table due - * to some manual user activity then they should be dropped by the user - * before invoking this function. - */ - - drop_cmd = psprintf("DROP TABLE %s.%s", - quote_identifier(NameStr(chunk->fd.schema_name)), - quote_identifier(NameStr(chunk->fd.table_name))); - data_nodes = list_make1((char *) node_name); - ts_dist_cmd_run_on_data_nodes(drop_cmd, data_nodes, true); - - /* - * This chunk might have this data node as primary, change that association - * if so. Then delete the chunk_id and node_name association. - */ - LockRelationOid(chunk->table_id, ShareUpdateExclusiveLock); - chunk_update_foreign_server_if_needed(chunk, serverid, false); - ts_chunk_data_node_delete_by_chunk_id_and_node_name(chunk->fd.id, node_name); -} diff --git a/tsl/src/data_node.c b/tsl/src/data_node.c index 4367dd8c163..a6c71d2d2c6 100644 --- a/tsl/src/data_node.c +++ b/tsl/src/data_node.c @@ -1204,7 +1204,6 @@ data_node_modify_hypertable_data_nodes(const char *node_name, List *hypertable_d const Chunk *chunk = ts_chunk_get_by_id(cdn->fd.chunk_id, true); LockRelationOid(chunk->table_id, ShareUpdateExclusiveLock); - chunk_update_foreign_server_if_needed(chunk, cdn->foreign_server_oid, false); ts_chunk_data_node_delete_by_chunk_id_and_node_name(cdn->fd.chunk_id, NameStr(cdn->fd.node_name)); } @@ -1554,43 +1553,6 @@ create_alter_data_node_tuple(TupleDesc tupdesc, const char *node_name, List *opt return heap_form_tuple(tupdesc, values, nulls); } -/* - * Switch data node to use for queries on chunks. - * - * When available=false it will switch from the given data node to another - * one, but only if the data node is currently used for queries on the chunk. - * - * When available=true it will switch to the given data node, if it is - * "primary" for the chunk (according to the current partitioning - * configuration). - */ -static void -switch_data_node_on_chunks(const ForeignServer *datanode, bool available) -{ - unsigned int failed_update_count = 0; - ScanIterator it = ts_chunk_data_nodes_scan_iterator_create(CurrentMemoryContext); - ts_chunk_data_nodes_scan_iterator_set_node_name(&it, datanode->servername); - - /* Scan for chunks that reference the given data node */ - ts_scanner_foreach(&it) - { - TupleTableSlot *slot = ts_scan_iterator_slot(&it); - bool PG_USED_FOR_ASSERTS_ONLY isnull = false; - Datum chunk_id = slot_getattr(slot, Anum_chunk_data_node_chunk_id, &isnull); - - Assert(!isnull); - - const Chunk *chunk = ts_chunk_get_by_id(DatumGetInt32(chunk_id), true); - if (!chunk_update_foreign_server_if_needed(chunk, datanode->serverid, available)) - failed_update_count++; - } - - if (!available && failed_update_count > 0) - elog(WARNING, "could not switch data node on %u chunks", failed_update_count); - - ts_scan_iterator_close(&it); -} - /* * Append new data node options. * @@ -1723,19 +1685,10 @@ data_node_alter(PG_FUNCTION_ARGS) alter_server_stmt.options = options; AlterForeignServer(&alter_server_stmt); - /* Drop stale chunks on the unavailable data node, if we are going to - * make it available again */ - if (!available_is_null && available && !ts_data_node_is_available_by_server(server)) - ts_chunk_drop_stale_chunks(node_name, NULL); - /* Make changes to the data node (foreign server object) visible so that * the changes are present when we switch "primary" data node on chunks */ CommandCounterIncrement(); - /* Update the currently used query data node on all affected chunks to - * reflect the new status of the data node */ - switch_data_node_on_chunks(server, available); - /* Add updated options last as they will take precedence over old options * when creating the result tuple. */ options = list_concat(current_options, options); diff --git a/tsl/src/init.c b/tsl/src/init.c index 7184ab03347..866af366dd9 100644 --- a/tsl/src/init.c +++ b/tsl/src/init.c @@ -182,48 +182,15 @@ CrossModuleFunctions tsl_cm_functions = { .decompress_target_segments = NULL, #endif - .data_node_add = data_node_add, - .data_node_delete = data_node_delete, - .data_node_attach = data_node_attach, - .data_node_ping = data_node_ping, - .data_node_detach = data_node_detach, - .data_node_alter = data_node_alter, - .data_node_allow_new_chunks = data_node_allow_new_chunks, - .data_node_block_new_chunks = data_node_block_new_chunks, - .chunk_set_default_data_node = chunk_set_default_data_node, .show_chunk = chunk_show, .create_compressed_chunk = tsl_create_compressed_chunk, .create_chunk = chunk_create, - .create_chunk_on_data_nodes = chunk_api_create_on_data_nodes, - .chunk_drop_replica = chunk_drop_replica, .chunk_freeze_chunk = chunk_freeze_chunk, .chunk_unfreeze_chunk = chunk_unfreeze_chunk, - .chunks_drop_stale = chunk_drop_stale_chunks, - .hypertable_make_distributed = hypertable_make_distributed, - .get_and_validate_data_node_list = hypertable_get_and_validate_data_nodes, - .remote_txn_id_in = remote_txn_id_in_pg, - .remote_txn_id_out = remote_txn_id_out_pg, - .remote_txn_heal_data_node = remote_txn_heal_data_node, - .remote_connection_cache_show = remote_connection_cache_show, .set_rel_pathlist = tsl_set_rel_pathlist, - .set_distributed_id = dist_util_set_id, - .set_distributed_peer_id = dist_util_set_peer_id, - .is_access_node_session = dist_util_is_access_node_session_on_data_node, - .remove_from_distributed_db = dist_util_remove_from_db, - .dist_remote_hypertable_info = dist_util_remote_hypertable_info, - .dist_remote_chunk_info = dist_util_remote_chunk_info, - .dist_remote_compressed_chunk_info = dist_util_remote_compressed_chunk_info, - .dist_remote_hypertable_index_info = dist_util_remote_hypertable_index_info, - .dist_update_stale_chunk_metadata = chunk_update_stale_metadata, - .validate_as_data_node = validate_data_node_settings, - .distributed_exec = ts_dist_cmd_exec, - .create_distributed_restore_point = create_distributed_restore_point, - .func_call_on_data_nodes = ts_dist_cmd_func_call_on_data_nodes, .chunk_get_relstats = chunk_api_get_chunk_relstats, .chunk_get_colstats = chunk_api_get_chunk_colstats, .chunk_create_empty_table = chunk_create_empty_table, - .chunk_create_replica_table = chunk_create_replica_table, - .hypertable_distributed_set_replication_factor = hypertable_set_replication_factor, .cache_syscache_invalidate = cache_syscache_invalidate, .recompress_chunk_segmentwise = tsl_recompress_chunk_segmentwise, .get_compressed_chunk_index_for_recompression = diff --git a/tsl/src/process_utility.c b/tsl/src/process_utility.c index b6a886a032a..f6e9946518f 100644 --- a/tsl/src/process_utility.c +++ b/tsl/src/process_utility.c @@ -14,8 +14,6 @@ #include "ts_catalog/continuous_agg.h" #include "hypertable_cache.h" #include "process_utility.h" -#include "remote/dist_commands.h" -#include "remote/connection_cache.h" /* AlterTableCmds that need tsl side processing invoke this function * we only process AddColumn command right now. diff --git a/tsl/test/shared/expected/compat.out b/tsl/test/shared/expected/compat.out index f7dc93785db..19f554702c1 100644 --- a/tsl/test/shared/expected/compat.out +++ b/tsl/test/shared/expected/compat.out @@ -254,9 +254,6 @@ WARNING: function _timescaledb_internal.relation_size(regclass) is deprecated a SELECT _timescaledb_internal.restart_background_workers(); WARNING: function _timescaledb_internal.restart_background_workers() is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version. ERROR: must be superuser to restart background workers -SELECT _timescaledb_internal.set_chunk_default_data_node(0,NULL); -WARNING: function _timescaledb_internal.set_chunk_default_data_node(regclass,name) is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version. -ERROR: invalid chunk: cannot be NULL SELECT _timescaledb_internal.show_chunk(0); WARNING: function _timescaledb_internal.show_chunk(regclass) is deprecated and has been moved to _timescaledb_functions schema. this compatibility function will be removed in a future version. ERROR: invalid Oid diff --git a/tsl/test/shared/expected/extension.out b/tsl/test/shared/expected/extension.out index f3a749f00b4..b2421ff85e7 100644 --- a/tsl/test/shared/expected/extension.out +++ b/tsl/test/shared/expected/extension.out @@ -121,7 +121,6 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text _timescaledb_functions.relation_size(regclass) _timescaledb_functions.repair_relation_acls() _timescaledb_functions.restart_background_workers() - _timescaledb_functions.set_chunk_default_data_node(regclass,name) _timescaledb_functions.show_chunk(regclass) _timescaledb_functions.start_background_workers() _timescaledb_functions.stop_background_workers() @@ -214,7 +213,6 @@ ORDER BY pronamespace::regnamespace::text COLLATE "C", p.oid::regprocedure::text _timescaledb_internal.recompress_chunk_segmentwise(regclass,boolean) _timescaledb_internal.relation_size(regclass) _timescaledb_internal.restart_background_workers() - _timescaledb_internal.set_chunk_default_data_node(regclass,name) _timescaledb_internal.show_chunk(regclass) _timescaledb_internal.start_background_workers() _timescaledb_internal.stop_background_workers() diff --git a/tsl/test/shared/sql/compat.sql b/tsl/test/shared/sql/compat.sql index e94cce6da23..337615729b1 100644 --- a/tsl/test/shared/sql/compat.sql +++ b/tsl/test/shared/sql/compat.sql @@ -62,7 +62,6 @@ SELECT _timescaledb_internal.range_value_to_pretty(0,0); SELECT _timescaledb_internal.recompress_chunk_segmentwise(0,true); SELECT _timescaledb_internal.relation_size(0); SELECT _timescaledb_internal.restart_background_workers(); -SELECT _timescaledb_internal.set_chunk_default_data_node(0,NULL); SELECT _timescaledb_internal.show_chunk(0); SELECT _timescaledb_internal.start_background_workers(); SELECT _timescaledb_internal.stop_background_workers();