Fix gapfill with prepared statements

The start and finish arguments for time_bucket_gapfill are removed
from the final execution. This adjustment used to happen in executor
but this patch changes this behaviour and removes them in the planning
phase and pass the original arguments to time_bucket_gapfill in
custom_private so in execution phase time_bucket_gapfill arguments
need not be adjusted.
This commit is contained in:
Sven Klemm 2019-03-26 05:28:01 +01:00 committed by Sven Klemm
parent 89cb73318d
commit 859b97f01c
8 changed files with 483 additions and 70 deletions

View File

@ -7,6 +7,7 @@ accidentally triggering the load of a previous DB version.**
## 1.3.0 (unreleased)
**Minor Features**
* #1112 Add support for window functions to gapfill
* #1062 Make constraint aware append parallel safe
* #1005 Enable creating indexes with one transaction per chunk
* #1007 Remove parent oid from find_children_oids result

View File

@ -500,6 +500,7 @@ gapfill_begin(CustomScanState *node, EState *estate, int eflags)
* extract arguments and to align gapfill_start
*/
FuncExpr *func = linitial(cscan->custom_private);
List *args = lfourth(cscan->custom_private);
TupleDesc tupledesc = state->csstate.ss.ps.ps_ResultTupleSlot->tts_tupleDescriptor;
List *targetlist = copyObject(state->csstate.ss.ps.plan->targetlist);
Node *entry;
@ -513,27 +514,26 @@ gapfill_begin(CustomScanState *node, EState *estate, int eflags)
state->scanslot = MakeSingleTupleTableSlot(tupledesc);
/* bucket_width */
if (!is_simple_expr(linitial(func->args)))
if (!is_simple_expr(linitial(args)))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid time_bucket_gapfill argument: bucket_width must be a simple "
"expression")));
arg_value = gapfill_exec_expr(state, linitial(func->args), &isnull);
arg_value = gapfill_exec_expr(state, linitial(args), &isnull);
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid time_bucket_gapfill argument: bucket_width cannot be NULL")));
state->gapfill_period = gapfill_period_get_internal(func->funcresulttype,
exprType(linitial(func->args)),
arg_value);
state->gapfill_period =
gapfill_period_get_internal(func->funcresulttype, exprType(linitial(args)), arg_value);
/*
* check if gapfill start was left out so we have to infer from WHERE
* clause
*/
if (is_const_null(lthird(func->args)))
if (is_const_null(lthird(args)))
{
int64 start = infer_gapfill_boundary(state, GAPFILL_START);
Const *expr = make_const_value_for_gapfill_internal(state->gapfill_typid, start);
@ -546,21 +546,21 @@ gapfill_begin(CustomScanState *node, EState *estate, int eflags)
* pass gapfill start through time_bucket so it is aligned with bucket
* start
*/
state->gapfill_start = align_with_time_bucket(state, lthird(func->args));
state->gapfill_start = align_with_time_bucket(state, lthird(args));
}
state->next_timestamp = state->gapfill_start;
/* gap fill end */
if (is_const_null(lfourth(func->args)))
if (is_const_null(lfourth(args)))
state->gapfill_end = infer_gapfill_boundary(state, GAPFILL_END);
else
{
if (!is_simple_expr(lfourth(func->args)))
if (!is_simple_expr(lfourth(args)))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid time_bucket_gapfill argument: finish must be a simple "
"expression")));
arg_value = gapfill_exec_expr(state, lfourth(func->args), &isnull);
arg_value = gapfill_exec_expr(state, lfourth(args), &isnull);
/*
* the default value for finish is NULL but this is checked above,
@ -576,9 +576,6 @@ gapfill_begin(CustomScanState *node, EState *estate, int eflags)
state->gapfill_end = gapfill_datum_get_internal(arg_value, func->funcresulttype);
}
/* remove start and end argument from time_bucket call */
func->args = list_make2(linitial(func->args), lsecond(func->args));
gapfill_state_initialize_columns(state);
/*

View File

@ -166,6 +166,7 @@ gapfill_plan_create(PlannerInfo *root, RelOptInfo *rel, struct CustomPath *path,
{
GapFillPath *gfpath = (GapFillPath *) path;
CustomScan *cscan = makeNode(CustomScan);
List *args = list_copy(gfpath->func->args);
cscan->scan.scanrelid = 0;
cscan->scan.plan.targetlist = tlist;
@ -175,7 +176,10 @@ gapfill_plan_create(PlannerInfo *root, RelOptInfo *rel, struct CustomPath *path,
cscan->methods = &gapfill_plan_methods;
cscan->custom_private =
list_make3(gfpath->func, root->parse->groupClause, root->parse->jointree);
list_make4(gfpath->func, root->parse->groupClause, root->parse->jointree, args);
/* remove start and end argument from time_bucket call */
gfpath->func->args = list_make2(linitial(gfpath->func->args), lsecond(gfpath->func->args));
return &cscan->scan.plan;
}

View File

@ -2116,3 +2116,334 @@ GROUP BY 3,4;
5 | 2 | red | 4
(10 rows)
-- test prepared statement
PREPARE prep_gapfill AS
SELECT
time_bucket_gapfill(1,time,0,5) as time,
locf(min(value))
FROM (VALUES (1,1),(2,2)) v(time,value)
GROUP BY 1;
-- execute 10 times to make sure turning it into generic plan works
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
EXECUTE prep_gapfill;
time | locf
------+------
0 |
1 | 1
2 | 2
3 | 2
4 | 2
(5 rows)
DEALLOCATE prep_gapfill;
-- test prepared statement with locf with lookup query
PREPARE prep_gapfill AS
SELECT
time_bucket_gapfill(5,time,0,11) AS time,
device_id,
sensor_id,
locf(min(value)::int,(SELECT 1/(SELECT 0) FROM metrics_int m2 WHERE m2.device_id=m1.device_id AND m2.sensor_id=m1.sensor_id ORDER BY time DESC LIMIT 1))
FROM metrics_int m1
WHERE time >= 0 AND time < 5
GROUP BY 1,2,3;
-- execute 10 times to make sure turning it into generic plan works
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | locf
------+-----------+-----------+------
0 | 1 | 1 | 5
5 | 1 | 1 | 5
10 | 1 | 1 | 5
(3 rows)
DEALLOCATE prep_gapfill;
-- test prepared statement with interpolate with lookup query
PREPARE prep_gapfill AS
SELECT
time_bucket_gapfill(5,time,0,11) AS time,
device_id,
sensor_id,
interpolate(
min(value),
(SELECT (time,value) FROM metrics_int m2
WHERE time<0 AND m2.device_id=m1.device_id AND m2.sensor_id=m1.sensor_id
ORDER BY time DESC LIMIT 1),
(SELECT (time,value) FROM metrics_int m2
WHERE time>10 AND m2.device_id=m1.device_id AND m2.sensor_id=m1.sensor_id
ORDER BY time LIMIT 1)
)
FROM metrics_int m1
WHERE time >= 0 AND time < 10
GROUP BY 1,2,3 ORDER BY 2,3,1;
-- execute 10 times to make sure turning it into generic plan works
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
EXECUTE prep_gapfill;
time | device_id | sensor_id | interpolate
------+-----------+-----------+------------------
0 | 1 | 1 | 5
5 | 1 | 1 | 4.75
10 | 1 | 1 | 4.5
0 | 1 | 2 | 4.76190476190476
5 | 1 | 2 | 10
10 | 1 | 2 | 4.21052631578947
(6 rows)
DEALLOCATE prep_gapfill;

View File

@ -114,17 +114,17 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Finalize GroupAggregate
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> Gather
Workers Planned: 1
-> Partial HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time")
-> Result
-> Append
-> Parallel Seq Scan on _hyper_1_1_chunk
@ -141,17 +141,17 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Finalize GroupAggregate
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> Gather
Workers Planned: 1
-> Partial HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time")
-> Result
-> Append
-> Parallel Seq Scan on _hyper_1_1_chunk
@ -168,17 +168,17 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Finalize GroupAggregate
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> Gather
Workers Planned: 1
-> Partial HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time")
-> Result
-> Append
-> Parallel Seq Scan on _hyper_1_1_chunk
@ -197,20 +197,20 @@ FROM gapfill_plan_test
GROUP BY 1
ORDER BY 2
LIMIT 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
Limit
-> Sort
Sort Key: (interpolate(avg(value), NULL::record, NULL::record))
-> Custom Scan (GapFill)
-> Finalize GroupAggregate
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> Gather
Workers Planned: 1
-> Partial HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time")
-> Result
-> Append
-> Parallel Seq Scan on _hyper_1_1_chunk

View File

@ -114,17 +114,17 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Finalize GroupAggregate
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time"))
-> Gather Merge
Workers Planned: 2
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time"))
-> Partial HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time")
-> Result
-> Parallel Append
-> Parallel Seq Scan on _hyper_1_2_chunk
@ -141,17 +141,17 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Finalize GroupAggregate
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time"))
-> Gather Merge
Workers Planned: 2
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time"))
-> Partial HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time")
-> Result
-> Parallel Append
-> Parallel Seq Scan on _hyper_1_2_chunk
@ -168,17 +168,17 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Finalize GroupAggregate
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time"))
-> Gather Merge
Workers Planned: 2
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time"))
-> Partial HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time")
-> Result
-> Parallel Append
-> Parallel Seq Scan on _hyper_1_2_chunk
@ -197,20 +197,20 @@ FROM gapfill_plan_test
GROUP BY 1
ORDER BY 2
LIMIT 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
Limit
-> Sort
Sort Key: (interpolate(avg(value), NULL::record, NULL::record))
-> Custom Scan (GapFill)
-> Finalize GroupAggregate
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Group Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time"))
-> Gather Merge
Workers Planned: 2
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time"))
-> Partial HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_2_chunk."time")
-> Result
-> Parallel Append
-> Parallel Seq Scan on _hyper_1_2_chunk

View File

@ -114,13 +114,13 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time")
-> Result
-> Append
-> Seq Scan on _hyper_1_1_chunk
@ -137,13 +137,13 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time")
-> Result
-> Append
-> Seq Scan on _hyper_1_1_chunk
@ -160,13 +160,13 @@ SELECT
FROM gapfill_plan_test
GROUP BY 1
ORDER BY 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------
Custom Scan (GapFill)
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time")
-> Result
-> Append
-> Seq Scan on _hyper_1_1_chunk
@ -185,16 +185,16 @@ FROM gapfill_plan_test
GROUP BY 1
ORDER BY 2
LIMIT 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Limit
-> Sort
Sort Key: (interpolate(avg(value), NULL::record, NULL::record))
-> Custom Scan (GapFill)
-> Sort
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone))
Sort Key: (time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time"))
-> HashAggregate
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time", 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone, 'Wed Dec 31 16:00:00 1969 PST'::timestamp with time zone)
Group Key: time_bucket_gapfill('@ 5 mins'::interval, _hyper_1_1_chunk."time")
-> Result
-> Append
-> Seq Scan on _hyper_1_1_chunk

View File

@ -1258,3 +1258,83 @@ SELECT
FROM (VALUES (1,'blue',1),(2,'red',2)) v(time,color,value)
GROUP BY 3,4;
-- test prepared statement
PREPARE prep_gapfill AS
SELECT
time_bucket_gapfill(1,time,0,5) as time,
locf(min(value))
FROM (VALUES (1,1),(2,2)) v(time,value)
GROUP BY 1;
-- execute 10 times to make sure turning it into generic plan works
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
DEALLOCATE prep_gapfill;
-- test prepared statement with locf with lookup query
PREPARE prep_gapfill AS
SELECT
time_bucket_gapfill(5,time,0,11) AS time,
device_id,
sensor_id,
locf(min(value)::int,(SELECT 1/(SELECT 0) FROM metrics_int m2 WHERE m2.device_id=m1.device_id AND m2.sensor_id=m1.sensor_id ORDER BY time DESC LIMIT 1))
FROM metrics_int m1
WHERE time >= 0 AND time < 5
GROUP BY 1,2,3;
-- execute 10 times to make sure turning it into generic plan works
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
DEALLOCATE prep_gapfill;
-- test prepared statement with interpolate with lookup query
PREPARE prep_gapfill AS
SELECT
time_bucket_gapfill(5,time,0,11) AS time,
device_id,
sensor_id,
interpolate(
min(value),
(SELECT (time,value) FROM metrics_int m2
WHERE time<0 AND m2.device_id=m1.device_id AND m2.sensor_id=m1.sensor_id
ORDER BY time DESC LIMIT 1),
(SELECT (time,value) FROM metrics_int m2
WHERE time>10 AND m2.device_id=m1.device_id AND m2.sensor_id=m1.sensor_id
ORDER BY time LIMIT 1)
)
FROM metrics_int m1
WHERE time >= 0 AND time < 10
GROUP BY 1,2,3 ORDER BY 2,3,1;
-- execute 10 times to make sure turning it into generic plan works
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
EXECUTE prep_gapfill;
DEALLOCATE prep_gapfill;