mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-18 19:59:48 +08:00
Change ChunkAppend file organization
This patch changes the organization of the ChunkAppend code. It removes all header files except chunk_append/chunk_append.h. It also merges exec.c and explain.c to remove unnecessary function exports, since the code from explain.c was only used by exec.c
This commit is contained in:
parent
cc89f1dc84
commit
077b2edbc5
@ -1,8 +1,6 @@
|
|||||||
# Add all *.c to sources in upperlevel directory
|
# Add all *.c to sources in upperlevel directory
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/chunk_append.c
|
${CMAKE_CURRENT_SOURCE_DIR}/chunk_append.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/exec.c
|
${CMAKE_CURRENT_SOURCE_DIR}/exec.c ${CMAKE_CURRENT_SOURCE_DIR}/planner.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/explain.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/planner.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/transform.c)
|
${CMAKE_CURRENT_SOURCE_DIR}/transform.c)
|
||||||
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
||||||
|
@ -26,6 +26,7 @@ extern Path *ts_chunk_append_path_create(PlannerInfo *root, RelOptInfo *rel, Hyp
|
|||||||
List *nested_oids);
|
List *nested_oids);
|
||||||
extern Plan *ts_chunk_append_plan_create(PlannerInfo *root, RelOptInfo *rel, CustomPath *path,
|
extern Plan *ts_chunk_append_plan_create(PlannerInfo *root, RelOptInfo *rel, CustomPath *path,
|
||||||
List *tlist, List *clauses, List *custom_plans);
|
List *tlist, List *clauses, List *custom_plans);
|
||||||
|
extern Node *ts_chunk_append_state_create(CustomScan *cscan);
|
||||||
|
|
||||||
extern bool ts_ordered_append_should_optimize(PlannerInfo *root, RelOptInfo *rel, Hypertable *ht,
|
extern bool ts_ordered_append_should_optimize(PlannerInfo *root, RelOptInfo *rel, Hypertable *ht,
|
||||||
List *join_conditions, int *order_attno,
|
List *join_conditions, int *order_attno,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
#include <fmgr.h>
|
#include <fmgr.h>
|
||||||
#include <miscadmin.h>
|
#include <miscadmin.h>
|
||||||
|
#include <catalog/pg_collation.h>
|
||||||
#include <executor/executor.h>
|
#include <executor/executor.h>
|
||||||
#include <executor/nodeSubplan.h>
|
#include <executor/nodeSubplan.h>
|
||||||
#include <nodes/bitmapset.h>
|
#include <nodes/bitmapset.h>
|
||||||
@ -18,23 +19,79 @@
|
|||||||
#include <optimizer/restrictinfo.h>
|
#include <optimizer/restrictinfo.h>
|
||||||
#include <parser/parsetree.h>
|
#include <parser/parsetree.h>
|
||||||
#include <rewrite/rewriteManip.h>
|
#include <rewrite/rewriteManip.h>
|
||||||
|
#include <utils/builtins.h>
|
||||||
#include <utils/memutils.h>
|
#include <utils/memutils.h>
|
||||||
|
#include <utils/ruleutils.h>
|
||||||
#include <utils/typcache.h>
|
#include <utils/typcache.h>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "nodes/chunk_append/exec.h"
|
|
||||||
#include "nodes/chunk_append/chunk_append.h"
|
#include "nodes/chunk_append/chunk_append.h"
|
||||||
#include "nodes/chunk_append/explain.h"
|
|
||||||
#include "loader/lwlocks.h"
|
#include "loader/lwlocks.h"
|
||||||
|
|
||||||
#define INVALID_SUBPLAN_INDEX -1
|
#define INVALID_SUBPLAN_INDEX -1
|
||||||
#define NO_MATCHING_SUBPLANS -2
|
#define NO_MATCHING_SUBPLANS -2
|
||||||
|
|
||||||
|
typedef struct ParallelChunkAppendState
|
||||||
|
{
|
||||||
|
int next_plan;
|
||||||
|
bool finished[FLEXIBLE_ARRAY_MEMBER];
|
||||||
|
} ParallelChunkAppendState;
|
||||||
|
|
||||||
|
typedef struct ChunkAppendState
|
||||||
|
{
|
||||||
|
CustomScanState csstate;
|
||||||
|
PlanState **subplanstates;
|
||||||
|
|
||||||
|
MemoryContext exclusion_ctx;
|
||||||
|
|
||||||
|
int num_subplans;
|
||||||
|
int first_partial_plan;
|
||||||
|
int filtered_first_partial_plan;
|
||||||
|
int current;
|
||||||
|
|
||||||
|
Oid ht_reloid;
|
||||||
|
bool startup_exclusion;
|
||||||
|
bool runtime_exclusion;
|
||||||
|
bool runtime_initialized;
|
||||||
|
uint32 limit;
|
||||||
|
|
||||||
|
/* list of subplans after planning */
|
||||||
|
List *initial_subplans;
|
||||||
|
/* list of constraints indexed like initial_subplans */
|
||||||
|
List *initial_constraints;
|
||||||
|
/* list of restrictinfo clauses indexed like initial_subplans */
|
||||||
|
List *initial_ri_clauses;
|
||||||
|
|
||||||
|
/* list of subplans after startup exclusion */
|
||||||
|
List *filtered_subplans;
|
||||||
|
/* list of relation constraints after startup exclusion */
|
||||||
|
List *filtered_constraints;
|
||||||
|
/* list of restrictinfo clauses after startup exclusion */
|
||||||
|
List *filtered_ri_clauses;
|
||||||
|
|
||||||
|
/* valid subplans for runtime exclusion */
|
||||||
|
Bitmapset *valid_subplans;
|
||||||
|
Bitmapset *params;
|
||||||
|
|
||||||
|
/* sort options if this append is ordered, only used for EXPLAIN */
|
||||||
|
List *sort_options;
|
||||||
|
|
||||||
|
/* number of loops and exclusions for EXPLAIN */
|
||||||
|
int runtime_number_loops;
|
||||||
|
int runtime_number_exclusions;
|
||||||
|
|
||||||
|
LWLock *lock;
|
||||||
|
ParallelContext *pcxt;
|
||||||
|
ParallelChunkAppendState *pstate;
|
||||||
|
void (*choose_next_subplan)(struct ChunkAppendState *);
|
||||||
|
} ChunkAppendState;
|
||||||
|
|
||||||
static TupleTableSlot *chunk_append_exec(CustomScanState *node);
|
static TupleTableSlot *chunk_append_exec(CustomScanState *node);
|
||||||
static void chunk_append_begin(CustomScanState *node, EState *estate, int eflags);
|
static void chunk_append_begin(CustomScanState *node, EState *estate, int eflags);
|
||||||
static void chunk_append_end(CustomScanState *node);
|
static void chunk_append_end(CustomScanState *node);
|
||||||
static void chunk_append_rescan(CustomScanState *node);
|
static void chunk_append_rescan(CustomScanState *node);
|
||||||
|
static void chunk_append_explain(CustomScanState *node, List *ancestors, ExplainState *es);
|
||||||
static Size chunk_append_estimate_dsm(CustomScanState *node, ParallelContext *pcxt);
|
static Size chunk_append_estimate_dsm(CustomScanState *node, ParallelContext *pcxt);
|
||||||
static void chunk_append_initialize_dsm(CustomScanState *node, ParallelContext *pcxt,
|
static void chunk_append_initialize_dsm(CustomScanState *node, ParallelContext *pcxt,
|
||||||
void *coordinate);
|
void *coordinate);
|
||||||
@ -47,7 +104,7 @@ static CustomExecMethods chunk_append_state_methods = {
|
|||||||
.ExecCustomScan = chunk_append_exec,
|
.ExecCustomScan = chunk_append_exec,
|
||||||
.EndCustomScan = chunk_append_end,
|
.EndCustomScan = chunk_append_end,
|
||||||
.ReScanCustomScan = chunk_append_rescan,
|
.ReScanCustomScan = chunk_append_rescan,
|
||||||
.ExplainCustomScan = ts_chunk_append_explain,
|
.ExplainCustomScan = chunk_append_explain,
|
||||||
.EstimateDSMCustomScan = chunk_append_estimate_dsm,
|
.EstimateDSMCustomScan = chunk_append_estimate_dsm,
|
||||||
.InitializeDSMCustomScan = chunk_append_initialize_dsm,
|
.InitializeDSMCustomScan = chunk_append_initialize_dsm,
|
||||||
.ReInitializeDSMCustomScan = chunk_append_reinitialize_dsm,
|
.ReInitializeDSMCustomScan = chunk_append_reinitialize_dsm,
|
||||||
@ -66,6 +123,10 @@ static List *constify_restrictinfo_params(PlannerInfo *root, EState *state, List
|
|||||||
static void initialize_constraints(ChunkAppendState *state, List *initial_rt_indexes);
|
static void initialize_constraints(ChunkAppendState *state, List *initial_rt_indexes);
|
||||||
static LWLock *chunk_append_get_lock_pointer(void);
|
static LWLock *chunk_append_get_lock_pointer(void);
|
||||||
|
|
||||||
|
static void show_sort_group_keys(ChunkAppendState *planstate, List *ancestors, ExplainState *es);
|
||||||
|
static void show_sortorder_options(StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation,
|
||||||
|
bool nullsFirst);
|
||||||
|
|
||||||
Node *
|
Node *
|
||||||
ts_chunk_append_state_create(CustomScan *cscan)
|
ts_chunk_append_state_create(CustomScan *cscan)
|
||||||
{
|
{
|
||||||
@ -929,3 +990,151 @@ initialize_constraints(ChunkAppendState *state, List *initial_rt_indexes)
|
|||||||
state->initial_constraints = constraints;
|
state->initial_constraints = constraints;
|
||||||
state->filtered_constraints = constraints;
|
state->filtered_constraints = constraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output additional information for EXPLAIN of a custom-scan plan node.
|
||||||
|
* This callback is optional. Common data stored in the ScanState,
|
||||||
|
* such as the target list and scan relation, will be shown even without
|
||||||
|
* this callback, but the callback allows the display of additional,
|
||||||
|
* private state.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
chunk_append_explain(CustomScanState *node, List *ancestors, ExplainState *es)
|
||||||
|
{
|
||||||
|
ChunkAppendState *state = (ChunkAppendState *) node;
|
||||||
|
|
||||||
|
if (state->sort_options != NIL)
|
||||||
|
show_sort_group_keys(state, ancestors, es);
|
||||||
|
|
||||||
|
if (es->verbose || es->format != EXPLAIN_FORMAT_TEXT)
|
||||||
|
ExplainPropertyBool("Startup Exclusion", state->startup_exclusion, es);
|
||||||
|
|
||||||
|
if (es->verbose || es->format != EXPLAIN_FORMAT_TEXT)
|
||||||
|
ExplainPropertyBool("Runtime Exclusion", state->runtime_exclusion, es);
|
||||||
|
|
||||||
|
if (state->startup_exclusion)
|
||||||
|
ExplainPropertyInteger("Chunks excluded during startup",
|
||||||
|
NULL,
|
||||||
|
list_length(state->initial_subplans) - list_length(node->custom_ps),
|
||||||
|
es);
|
||||||
|
|
||||||
|
if (state->runtime_exclusion && state->runtime_number_loops > 0)
|
||||||
|
{
|
||||||
|
int avg_excluded = state->runtime_number_exclusions / state->runtime_number_loops;
|
||||||
|
ExplainPropertyInteger("Chunks excluded during runtime", NULL, avg_excluded, es);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* adjusted from postgresql explain.c
|
||||||
|
* since we have to keep the state in custom_private our sort state
|
||||||
|
* is in lists instead of arrays
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
show_sort_group_keys(ChunkAppendState *state, List *ancestors, ExplainState *es)
|
||||||
|
{
|
||||||
|
Plan *plan = state->csstate.ss.ps.plan;
|
||||||
|
List *context;
|
||||||
|
List *result = NIL;
|
||||||
|
StringInfoData sortkeybuf;
|
||||||
|
bool useprefix;
|
||||||
|
int keyno;
|
||||||
|
int nkeys = list_length(linitial(state->sort_options));
|
||||||
|
List *sort_indexes = linitial(state->sort_options);
|
||||||
|
List *sort_ops = lsecond(state->sort_options);
|
||||||
|
List *sort_collations = lthird(state->sort_options);
|
||||||
|
List *sort_nulls = lfourth(state->sort_options);
|
||||||
|
|
||||||
|
if (nkeys <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
initStringInfo(&sortkeybuf);
|
||||||
|
|
||||||
|
/* Set up deparsing context */
|
||||||
|
#if PG13_GE
|
||||||
|
context = set_deparse_context_plan(es->deparse_cxt, plan, ancestors);
|
||||||
|
#else
|
||||||
|
context = set_deparse_context_planstate(es->deparse_cxt, (Node *) state, ancestors);
|
||||||
|
#endif
|
||||||
|
useprefix = (list_length(es->rtable) > 1 || es->verbose);
|
||||||
|
|
||||||
|
for (keyno = 0; keyno < nkeys; keyno++)
|
||||||
|
{
|
||||||
|
/* find key expression in tlist */
|
||||||
|
AttrNumber keyresno = list_nth_oid(sort_indexes, keyno);
|
||||||
|
TargetEntry *target =
|
||||||
|
get_tle_by_resno(castNode(CustomScan, plan)->custom_scan_tlist, keyresno);
|
||||||
|
char *exprstr;
|
||||||
|
|
||||||
|
if (!target)
|
||||||
|
elog(ERROR, "no tlist entry for key %d", keyresno);
|
||||||
|
/* Deparse the expression, showing any top-level cast */
|
||||||
|
exprstr = deparse_expression((Node *) target->expr, context, useprefix, true);
|
||||||
|
resetStringInfo(&sortkeybuf);
|
||||||
|
appendStringInfoString(&sortkeybuf, exprstr);
|
||||||
|
/* Append sort order information, if relevant */
|
||||||
|
if (sort_ops != NIL)
|
||||||
|
show_sortorder_options(&sortkeybuf,
|
||||||
|
(Node *) target->expr,
|
||||||
|
list_nth_oid(sort_ops, keyno),
|
||||||
|
list_nth_oid(sort_collations, keyno),
|
||||||
|
list_nth_oid(sort_nulls, keyno));
|
||||||
|
/* Emit one property-list item per sort key */
|
||||||
|
result = lappend(result, pstrdup(sortkeybuf.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExplainPropertyList("Order", result, es);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copied verbatim from postgresql explain.c */
|
||||||
|
static void
|
||||||
|
show_sortorder_options(StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation,
|
||||||
|
bool nullsFirst)
|
||||||
|
{
|
||||||
|
Oid sortcoltype = exprType(sortexpr);
|
||||||
|
bool reverse = false;
|
||||||
|
TypeCacheEntry *typentry;
|
||||||
|
|
||||||
|
typentry = lookup_type_cache(sortcoltype, TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print COLLATE if it's not default. There are some cases where this is
|
||||||
|
* redundant, eg if expression is a column whose declared collation is
|
||||||
|
* that collation, but it's hard to distinguish that here.
|
||||||
|
*/
|
||||||
|
if (OidIsValid(collation) && collation != DEFAULT_COLLATION_OID)
|
||||||
|
{
|
||||||
|
char *collname = get_collation_name(collation);
|
||||||
|
|
||||||
|
if (collname == NULL)
|
||||||
|
elog(ERROR, "cache lookup failed for collation %u", collation);
|
||||||
|
appendStringInfo(buf, " COLLATE %s", quote_identifier(collname));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print direction if not ASC, or USING if non-default sort operator */
|
||||||
|
if (sortOperator == typentry->gt_opr)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, " DESC");
|
||||||
|
reverse = true;
|
||||||
|
}
|
||||||
|
else if (sortOperator != typentry->lt_opr)
|
||||||
|
{
|
||||||
|
char *opname = get_opname(sortOperator);
|
||||||
|
|
||||||
|
if (opname == NULL)
|
||||||
|
elog(ERROR, "cache lookup failed for operator %u", sortOperator);
|
||||||
|
appendStringInfo(buf, " USING %s", opname);
|
||||||
|
/* Determine whether operator would be considered ASC or DESC */
|
||||||
|
(void) get_equality_op_for_ordering_op(sortOperator, &reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add NULLS FIRST/LAST only if it wouldn't be default */
|
||||||
|
if (nullsFirst && !reverse)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, " NULLS FIRST");
|
||||||
|
}
|
||||||
|
else if (!nullsFirst && reverse)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, " NULLS LAST");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file and its contents are licensed under the Apache License 2.0.
|
|
||||||
* Please see the included NOTICE for copyright information and
|
|
||||||
* LICENSE-APACHE for a copy of the license.
|
|
||||||
*/
|
|
||||||
#ifndef TIMESCALEDB_CHUNK_APPEND_EXEC_H
|
|
||||||
#define TIMESCALEDB_CHUNK_APPEND_EXEC_H
|
|
||||||
|
|
||||||
#include <postgres.h>
|
|
||||||
#include <nodes/bitmapset.h>
|
|
||||||
#include <nodes/extensible.h>
|
|
||||||
|
|
||||||
typedef struct ParallelChunkAppendState
|
|
||||||
{
|
|
||||||
int next_plan;
|
|
||||||
bool finished[FLEXIBLE_ARRAY_MEMBER];
|
|
||||||
} ParallelChunkAppendState;
|
|
||||||
|
|
||||||
typedef struct ChunkAppendState
|
|
||||||
{
|
|
||||||
CustomScanState csstate;
|
|
||||||
PlanState **subplanstates;
|
|
||||||
|
|
||||||
MemoryContext exclusion_ctx;
|
|
||||||
|
|
||||||
int num_subplans;
|
|
||||||
int first_partial_plan;
|
|
||||||
int filtered_first_partial_plan;
|
|
||||||
int current;
|
|
||||||
|
|
||||||
Oid ht_reloid;
|
|
||||||
bool startup_exclusion;
|
|
||||||
bool runtime_exclusion;
|
|
||||||
bool runtime_initialized;
|
|
||||||
uint32 limit;
|
|
||||||
|
|
||||||
/* list of subplans after planning */
|
|
||||||
List *initial_subplans;
|
|
||||||
/* list of constraints indexed like initial_subplans */
|
|
||||||
List *initial_constraints;
|
|
||||||
/* list of restrictinfo clauses indexed like initial_subplans */
|
|
||||||
List *initial_ri_clauses;
|
|
||||||
|
|
||||||
/* list of subplans after startup exclusion */
|
|
||||||
List *filtered_subplans;
|
|
||||||
/* list of relation constraints after startup exclusion */
|
|
||||||
List *filtered_constraints;
|
|
||||||
/* list of restrictinfo clauses after startup exclusion */
|
|
||||||
List *filtered_ri_clauses;
|
|
||||||
|
|
||||||
/* valid subplans for runtime exclusion */
|
|
||||||
Bitmapset *valid_subplans;
|
|
||||||
Bitmapset *params;
|
|
||||||
|
|
||||||
/* sort options if this append is ordered, only used for EXPLAIN */
|
|
||||||
List *sort_options;
|
|
||||||
|
|
||||||
/* number of loops and exclusions for EXPLAIN */
|
|
||||||
int runtime_number_loops;
|
|
||||||
int runtime_number_exclusions;
|
|
||||||
|
|
||||||
LWLock *lock;
|
|
||||||
ParallelContext *pcxt;
|
|
||||||
ParallelChunkAppendState *pstate;
|
|
||||||
void (*choose_next_subplan)(struct ChunkAppendState *);
|
|
||||||
} ChunkAppendState;
|
|
||||||
|
|
||||||
extern Node *ts_chunk_append_state_create(CustomScan *cscan);
|
|
||||||
|
|
||||||
#endif /* TIMESCALEDB_CHUNK_APPEND_EXEC_H */
|
|
@ -1,173 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file and its contents are licensed under the Apache License 2.0.
|
|
||||||
* Please see the included NOTICE for copyright information and
|
|
||||||
* LICENSE-APACHE for a copy of the license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <postgres.h>
|
|
||||||
#include <catalog/pg_collation.h>
|
|
||||||
#include <commands/explain.h>
|
|
||||||
#include <nodes/execnodes.h>
|
|
||||||
#include <nodes/nodeFuncs.h>
|
|
||||||
#include <nodes/parsenodes.h>
|
|
||||||
#include <parser/parsetree.h>
|
|
||||||
#include <utils/builtins.h>
|
|
||||||
#include <utils/lsyscache.h>
|
|
||||||
#include <utils/ruleutils.h>
|
|
||||||
#include <utils/typcache.h>
|
|
||||||
|
|
||||||
#include "nodes/chunk_append/exec.h"
|
|
||||||
#include "nodes/chunk_append/explain.h"
|
|
||||||
#include "compat/compat.h"
|
|
||||||
|
|
||||||
static void show_sort_group_keys(ChunkAppendState *planstate, List *ancestors, ExplainState *es);
|
|
||||||
static void show_sortorder_options(StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation,
|
|
||||||
bool nullsFirst);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Output additional information for EXPLAIN of a custom-scan plan node.
|
|
||||||
* This callback is optional. Common data stored in the ScanState,
|
|
||||||
* such as the target list and scan relation, will be shown even without
|
|
||||||
* this callback, but the callback allows the display of additional,
|
|
||||||
* private state.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ts_chunk_append_explain(CustomScanState *node, List *ancestors, ExplainState *es)
|
|
||||||
{
|
|
||||||
ChunkAppendState *state = (ChunkAppendState *) node;
|
|
||||||
|
|
||||||
if (state->sort_options != NIL)
|
|
||||||
show_sort_group_keys(state, ancestors, es);
|
|
||||||
|
|
||||||
if (es->verbose || es->format != EXPLAIN_FORMAT_TEXT)
|
|
||||||
ExplainPropertyBool("Startup Exclusion", state->startup_exclusion, es);
|
|
||||||
|
|
||||||
if (es->verbose || es->format != EXPLAIN_FORMAT_TEXT)
|
|
||||||
ExplainPropertyBool("Runtime Exclusion", state->runtime_exclusion, es);
|
|
||||||
|
|
||||||
if (state->startup_exclusion)
|
|
||||||
ExplainPropertyInteger("Chunks excluded during startup",
|
|
||||||
NULL,
|
|
||||||
list_length(state->initial_subplans) - list_length(node->custom_ps),
|
|
||||||
es);
|
|
||||||
|
|
||||||
if (state->runtime_exclusion && state->runtime_number_loops > 0)
|
|
||||||
{
|
|
||||||
int avg_excluded = state->runtime_number_exclusions / state->runtime_number_loops;
|
|
||||||
ExplainPropertyInteger("Chunks excluded during runtime", NULL, avg_excluded, es);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* adjusted from postgresql explain.c
|
|
||||||
* since we have to keep the state in custom_private our sort state
|
|
||||||
* is in lists instead of arrays
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
show_sort_group_keys(ChunkAppendState *state, List *ancestors, ExplainState *es)
|
|
||||||
{
|
|
||||||
Plan *plan = state->csstate.ss.ps.plan;
|
|
||||||
List *context;
|
|
||||||
List *result = NIL;
|
|
||||||
StringInfoData sortkeybuf;
|
|
||||||
bool useprefix;
|
|
||||||
int keyno;
|
|
||||||
int nkeys = list_length(linitial(state->sort_options));
|
|
||||||
List *sort_indexes = linitial(state->sort_options);
|
|
||||||
List *sort_ops = lsecond(state->sort_options);
|
|
||||||
List *sort_collations = lthird(state->sort_options);
|
|
||||||
List *sort_nulls = lfourth(state->sort_options);
|
|
||||||
|
|
||||||
if (nkeys <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
initStringInfo(&sortkeybuf);
|
|
||||||
|
|
||||||
/* Set up deparsing context */
|
|
||||||
#if PG13_GE
|
|
||||||
context = set_deparse_context_plan(es->deparse_cxt, plan, ancestors);
|
|
||||||
#else
|
|
||||||
context = set_deparse_context_planstate(es->deparse_cxt, (Node *) state, ancestors);
|
|
||||||
#endif
|
|
||||||
useprefix = (list_length(es->rtable) > 1 || es->verbose);
|
|
||||||
|
|
||||||
for (keyno = 0; keyno < nkeys; keyno++)
|
|
||||||
{
|
|
||||||
/* find key expression in tlist */
|
|
||||||
AttrNumber keyresno = list_nth_oid(sort_indexes, keyno);
|
|
||||||
TargetEntry *target =
|
|
||||||
get_tle_by_resno(castNode(CustomScan, plan)->custom_scan_tlist, keyresno);
|
|
||||||
char *exprstr;
|
|
||||||
|
|
||||||
if (!target)
|
|
||||||
elog(ERROR, "no tlist entry for key %d", keyresno);
|
|
||||||
/* Deparse the expression, showing any top-level cast */
|
|
||||||
exprstr = deparse_expression((Node *) target->expr, context, useprefix, true);
|
|
||||||
resetStringInfo(&sortkeybuf);
|
|
||||||
appendStringInfoString(&sortkeybuf, exprstr);
|
|
||||||
/* Append sort order information, if relevant */
|
|
||||||
if (sort_ops != NIL)
|
|
||||||
show_sortorder_options(&sortkeybuf,
|
|
||||||
(Node *) target->expr,
|
|
||||||
list_nth_oid(sort_ops, keyno),
|
|
||||||
list_nth_oid(sort_collations, keyno),
|
|
||||||
list_nth_oid(sort_nulls, keyno));
|
|
||||||
/* Emit one property-list item per sort key */
|
|
||||||
result = lappend(result, pstrdup(sortkeybuf.data));
|
|
||||||
}
|
|
||||||
|
|
||||||
ExplainPropertyList("Order", result, es);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copied verbatim from postgresql explain.c */
|
|
||||||
static void
|
|
||||||
show_sortorder_options(StringInfo buf, Node *sortexpr, Oid sortOperator, Oid collation,
|
|
||||||
bool nullsFirst)
|
|
||||||
{
|
|
||||||
Oid sortcoltype = exprType(sortexpr);
|
|
||||||
bool reverse = false;
|
|
||||||
TypeCacheEntry *typentry;
|
|
||||||
|
|
||||||
typentry = lookup_type_cache(sortcoltype, TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print COLLATE if it's not default. There are some cases where this is
|
|
||||||
* redundant, eg if expression is a column whose declared collation is
|
|
||||||
* that collation, but it's hard to distinguish that here.
|
|
||||||
*/
|
|
||||||
if (OidIsValid(collation) && collation != DEFAULT_COLLATION_OID)
|
|
||||||
{
|
|
||||||
char *collname = get_collation_name(collation);
|
|
||||||
|
|
||||||
if (collname == NULL)
|
|
||||||
elog(ERROR, "cache lookup failed for collation %u", collation);
|
|
||||||
appendStringInfo(buf, " COLLATE %s", quote_identifier(collname));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print direction if not ASC, or USING if non-default sort operator */
|
|
||||||
if (sortOperator == typentry->gt_opr)
|
|
||||||
{
|
|
||||||
appendStringInfoString(buf, " DESC");
|
|
||||||
reverse = true;
|
|
||||||
}
|
|
||||||
else if (sortOperator != typentry->lt_opr)
|
|
||||||
{
|
|
||||||
char *opname = get_opname(sortOperator);
|
|
||||||
|
|
||||||
if (opname == NULL)
|
|
||||||
elog(ERROR, "cache lookup failed for operator %u", sortOperator);
|
|
||||||
appendStringInfo(buf, " USING %s", opname);
|
|
||||||
/* Determine whether operator would be considered ASC or DESC */
|
|
||||||
(void) get_equality_op_for_ordering_op(sortOperator, &reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add NULLS FIRST/LAST only if it wouldn't be default */
|
|
||||||
if (nullsFirst && !reverse)
|
|
||||||
{
|
|
||||||
appendStringInfoString(buf, " NULLS FIRST");
|
|
||||||
}
|
|
||||||
else if (!nullsFirst && reverse)
|
|
||||||
{
|
|
||||||
appendStringInfoString(buf, " NULLS LAST");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file and its contents are licensed under the Apache License 2.0.
|
|
||||||
* Please see the included NOTICE for copyright information and
|
|
||||||
* LICENSE-APACHE for a copy of the license.
|
|
||||||
*/
|
|
||||||
#ifndef TIMESCALEDB_CHUNK_APPEND_EXPLAIN_H
|
|
||||||
#define TIMESCALEDB_CHUNK_APPEND_EXPLAIN_H
|
|
||||||
|
|
||||||
#include <postgres.h>
|
|
||||||
#include <commands/explain.h>
|
|
||||||
#include <nodes/execnodes.h>
|
|
||||||
|
|
||||||
void ts_chunk_append_explain(CustomScanState *node, List *ancestors, ExplainState *es);
|
|
||||||
|
|
||||||
#endif /* TIMESCALEDB_CHUNK_APPEND_EXPLAIN_H */
|
|
@ -21,7 +21,6 @@
|
|||||||
#include <parser/parsetree.h>
|
#include <parser/parsetree.h>
|
||||||
|
|
||||||
#include "nodes/chunk_append/chunk_append.h"
|
#include "nodes/chunk_append/chunk_append.h"
|
||||||
#include "nodes/chunk_append/exec.h"
|
|
||||||
#include "nodes/chunk_append/transform.h"
|
#include "nodes/chunk_append/transform.h"
|
||||||
#include "import/planner.h"
|
#include "import/planner.h"
|
||||||
#include "guc.h"
|
#include "guc.h"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user