Skip to content

Commit 2e6bf5b

Browse files
Allow subquery results which are exec params as gapfill arguments
1 parent 8ae6039 commit 2e6bf5b

7 files changed

Lines changed: 711 additions & 73 deletions

File tree

tsl/src/nodes/gapfill/gapfill_exec.c

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ is_simple_expr_walker(Node *node, void *context)
319319
case T_CaseWhen:
320320
break;
321321
case T_Param:
322-
if (castNode(Param, node)->paramkind != PARAM_EXTERN)
322+
if (castNode(Param, node)->paramkind != PARAM_EXTERN &&
323+
castNode(Param, node)->paramkind != PARAM_EXEC)
323324
{
324325
return true;
325326
}
@@ -799,30 +800,12 @@ gapfill_advance_timestamp(GapFillState *state)
799800
}
800801
}
801802

802-
/*
803-
* Initialize the scan state
804-
*/
805803
static void
806-
gapfill_begin(CustomScanState *node, EState *estate, int eflags)
804+
gapfill_initialize_arguments(GapFillState *state)
807805
{
808-
GapFillState *state = (GapFillState *) node;
809-
CustomScan *cscan = castNode(CustomScan, state->csstate.ss.ps.plan);
810-
811-
/*
812-
* this is the time_bucket_gapfill call from the plan which is used to
813-
* extract arguments and to align gapfill_start
814-
*/
815-
FuncExpr *func = list_nth(cscan->custom_private, GFP_GapfillFunc);
816-
TupleDesc tupledesc = state->csstate.ss.ps.ps_ResultTupleSlot->tts_tupleDescriptor;
817-
List *targetlist = copyObject(state->csstate.ss.ps.plan->targetlist);
818806
bool isnull;
819807
Datum arg_value;
820808

821-
state->gapfill_typid = func->funcresulttype;
822-
state->state = FETCHED_NONE;
823-
state->subslot = MakeSingleTupleTableSlot(tupledesc, &TTSOpsVirtual);
824-
state->scanslot = MakeSingleTupleTableSlot(tupledesc, &TTSOpsVirtual);
825-
826809
/* bucket_width */
827810
if (!is_simple_expr(linitial(state->args)))
828811
{
@@ -840,7 +823,7 @@ gapfill_begin(CustomScanState *node, EState *estate, int eflags)
840823
errmsg("invalid time_bucket_gapfill argument: bucket_width cannot be NULL")));
841824
}
842825

843-
state->gapfill_period = gapfill_period_get_internal(func->funcresulttype,
826+
state->gapfill_period = gapfill_period_get_internal(state->gapfill_typid,
844827
exprType(linitial(state->args)),
845828
arg_value,
846829
&state->gapfill_interval);
@@ -907,8 +890,31 @@ gapfill_begin(CustomScanState *node, EState *estate, int eflags)
907890
errhint("Specify start and finish as arguments or in the WHERE clause.")));
908891
}
909892

910-
state->gapfill_end = gapfill_datum_get_internal(arg_value, func->funcresulttype);
893+
state->gapfill_end = gapfill_datum_get_internal(arg_value, state->gapfill_typid);
911894
}
895+
}
896+
897+
/*
898+
* Initialize the scan state
899+
*/
900+
static void
901+
gapfill_begin(CustomScanState *node, EState *estate, int eflags)
902+
{
903+
GapFillState *state = (GapFillState *) node;
904+
CustomScan *cscan = castNode(CustomScan, state->csstate.ss.ps.plan);
905+
906+
/*
907+
* this is the time_bucket_gapfill call from the plan which is used to
908+
* extract arguments and to align gapfill_start
909+
*/
910+
FuncExpr *func = list_nth(cscan->custom_private, GFP_GapfillFunc);
911+
TupleDesc tupledesc = state->csstate.ss.ps.ps_ResultTupleSlot->tts_tupleDescriptor;
912+
List *targetlist = copyObject(state->csstate.ss.ps.plan->targetlist);
913+
914+
state->gapfill_typid = func->funcresulttype;
915+
state->state = PREFETCH;
916+
state->subslot = MakeSingleTupleTableSlot(tupledesc, &TTSOpsVirtual);
917+
state->scanslot = MakeSingleTupleTableSlot(tupledesc, &TTSOpsVirtual);
912918

913919
gapfill_state_initialize_columns(state, targetlist);
914920

@@ -939,6 +945,12 @@ gapfill_exec(CustomScanState *node)
939945
{
940946
CHECK_FOR_INTERRUPTS();
941947

948+
if (PREFETCH == state->state)
949+
{
950+
gapfill_initialize_arguments(state);
951+
state->state = FETCHED_NONE;
952+
}
953+
942954
/* fetch next tuple from subplan */
943955
if (FETCHED_NONE == state->state)
944956
{
@@ -1043,6 +1055,7 @@ gapfill_rescan(CustomScanState *node)
10431055
ExecReScan(linitial(node->custom_ps));
10441056
}
10451057

1058+
gapfill_initialize_arguments(state);
10461059
state->state = FETCHED_NONE;
10471060
state->next_timestamp = state->gapfill_start;
10481061
state->next_offset = state->gapfill_interval;

tsl/src/nodes/gapfill/gapfill_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
*/
4747
typedef enum GapFillFetchState
4848
{
49+
PREFETCH,
4950
FETCHED_NONE,
5051
FETCHED_ONE,
5152
FETCHED_NEXT_GROUP,

tsl/test/shared/expected/gapfill-15.out

Lines changed: 154 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,21 +1126,26 @@ SELECT
11261126
FROM (VALUES ('2000-01-01'::timestamptz),('2000-02-01'::timestamptz)) v(time)
11271127
GROUP BY 1;
11281128
ERROR: invalid time_bucket_gapfill argument: bucket_width must be greater than 0
1129-
-- test subqueries as interval, start and stop (not supported atm)
1129+
-- nonsimple expression (var) as gapfill bucket width, start and finish
11301130
SELECT
1131-
time_bucket_gapfill((SELECT 1),time,1,11)
1132-
FROM (VALUES (1),(2)) v(time)
1133-
GROUP BY 1;
1131+
time_bucket_gapfill(polling_interval,time),
1132+
m1.device_id,
1133+
locf(avg(v1))
1134+
FROM metrics_tstz m1, (VALUES(1, '10m'::interval),(2, '20m'::interval), (3, '30m'::interval)) dev(device_id, polling_interval)
1135+
WHERE m1.device_id = dev.device_id AND time >= (select min(time) from metrics_tstz m2) AND time < (select max(time) from metrics_tstz m2)
1136+
GROUP BY 1,2 ORDER BY 2,1;
11341137
ERROR: invalid time_bucket_gapfill argument: bucket_width must be a simple expression
11351138
SELECT
1136-
time_bucket_gapfill(1,time,(SELECT 1),11)
1137-
FROM (VALUES (1),(2)) v(time)
1138-
GROUP BY 1;
1139+
time_bucket_gapfill(1, time, time - 10, 100),
1140+
locf(avg(value))
1141+
FROM metrics_int m1
1142+
GROUP BY 1 ORDER BY 1;
11391143
ERROR: invalid time_bucket_gapfill argument: start must be a simple expression
11401144
SELECT
1141-
time_bucket_gapfill(1,time,1,(SELECT 11))
1142-
FROM (VALUES (1),(2)) v(time)
1143-
GROUP BY 1;
1145+
time_bucket_gapfill(1, time, -100, time + 10),
1146+
locf(avg(value))
1147+
FROM metrics_int m1
1148+
GROUP BY 1 ORDER BY 1;
11441149
ERROR: invalid time_bucket_gapfill argument: finish must be a simple expression
11451150
\set ON_ERROR_STOP 1
11461151
-- test time_bucket_gapfill without aggregation
@@ -3448,3 +3453,142 @@ EXECUTE coalesce_tz_test(NULL);
34483453
DEALLOCATE coalesce_tz_test;
34493454
RESET plan_cache_mode;
34503455
DROP TABLE gf_tz_test;
3456+
-- test subqueries as bucket width, start and stop
3457+
SELECT
3458+
time_bucket_gapfill((SELECT 1),time,1,11)
3459+
FROM (VALUES (1),(2)) v(time)
3460+
GROUP BY 1;
3461+
time_bucket_gapfill
3462+
---------------------
3463+
1
3464+
2
3465+
3
3466+
4
3467+
5
3468+
6
3469+
7
3470+
8
3471+
9
3472+
10
3473+
3474+
SELECT
3475+
time_bucket_gapfill(1,time,(SELECT 1),11)
3476+
FROM (VALUES (1),(2)) v(time)
3477+
GROUP BY 1;
3478+
time_bucket_gapfill
3479+
---------------------
3480+
1
3481+
2
3482+
3
3483+
4
3484+
5
3485+
6
3486+
7
3487+
8
3488+
9
3489+
10
3490+
3491+
SELECT
3492+
time_bucket_gapfill(1,time,1,(SELECT 11))
3493+
FROM (VALUES (1),(2)) v(time)
3494+
GROUP BY 1;
3495+
time_bucket_gapfill
3496+
---------------------
3497+
1
3498+
2
3499+
3
3500+
4
3501+
5
3502+
6
3503+
7
3504+
8
3505+
9
3506+
10
3507+
3508+
-- Fill gaps between min and max time in the table
3509+
SELECT
3510+
time_bucket_gapfill('10m'::interval,time),
3511+
locf(avg(v1))
3512+
FROM metrics_tstz m1
3513+
WHERE time >= (select min(time) from metrics_tstz m2) AND time < (select max(time) from metrics_tstz m2)
3514+
GROUP BY 1 ORDER BY 1;
3515+
time_bucket_gapfill | locf
3516+
------------------------------+------
3517+
Mon Jan 01 05:00:00 2018 PST | 0.7
3518+
Mon Jan 01 05:10:00 2018 PST | 0.7
3519+
Mon Jan 01 05:20:00 2018 PST | 0.7
3520+
Mon Jan 01 05:30:00 2018 PST | 0.7
3521+
Mon Jan 01 05:40:00 2018 PST | 0.7
3522+
Mon Jan 01 05:50:00 2018 PST | 0.7
3523+
Mon Jan 01 06:00:00 2018 PST | 0.7
3524+
Mon Jan 01 06:10:00 2018 PST | 0.7
3525+
Mon Jan 01 06:20:00 2018 PST | 0.7
3526+
Mon Jan 01 06:30:00 2018 PST | 0.7
3527+
Mon Jan 01 06:40:00 2018 PST | 0.7
3528+
Mon Jan 01 06:50:00 2018 PST | 0.7
3529+
3530+
-- Fill gaps between min and max time in the table for each device
3531+
SELECT
3532+
time_bucket_gapfill('20m'::interval,time),
3533+
device_id,
3534+
locf(avg(v1))
3535+
FROM metrics_tstz m1
3536+
WHERE time >= (select min(time) from metrics_tstz m2) AND time < (select max(time) from metrics_tstz m2)
3537+
GROUP BY 1,2 ORDER BY 2,1;
3538+
time_bucket_gapfill | device_id | locf
3539+
------------------------------+-----------+------
3540+
Mon Jan 01 05:00:00 2018 PST | 1 | 0.5
3541+
Mon Jan 01 05:20:00 2018 PST | 1 | 0.5
3542+
Mon Jan 01 05:40:00 2018 PST | 1 | 0.5
3543+
Mon Jan 01 06:00:00 2018 PST | 1 | 0.5
3544+
Mon Jan 01 06:20:00 2018 PST | 1 | 0.5
3545+
Mon Jan 01 06:40:00 2018 PST | 1 | 0.5
3546+
Mon Jan 01 05:00:00 2018 PST | 2 | 0.7
3547+
Mon Jan 01 05:20:00 2018 PST | 2 | 0.7
3548+
Mon Jan 01 05:40:00 2018 PST | 2 | 0.7
3549+
Mon Jan 01 06:00:00 2018 PST | 2 | 0.7
3550+
Mon Jan 01 06:20:00 2018 PST | 2 | 0.7
3551+
Mon Jan 01 06:40:00 2018 PST | 2 | 0.7
3552+
Mon Jan 01 05:00:00 2018 PST | 3 | 0.9
3553+
Mon Jan 01 05:20:00 2018 PST | 3 | 0.9
3554+
Mon Jan 01 05:40:00 2018 PST | 3 | 0.9
3555+
Mon Jan 01 06:00:00 2018 PST | 3 | 0.9
3556+
Mon Jan 01 06:20:00 2018 PST | 3 | 0.9
3557+
Mon Jan 01 06:40:00 2018 PST | 3 | 0.9
3558+
3559+
-- Fill gaps with individual bucket width for each device
3560+
SELECT sq.device_id, bucket, value
3561+
FROM (VALUES(1, '10m'::interval),(2, '20m'::interval), (3, '30m'::interval)) dev(device_id, polling_interval)
3562+
INNER JOIN LATERAL (
3563+
SELECT
3564+
time_bucket_gapfill(dev.polling_interval,time) bucket,
3565+
m1.device_id,
3566+
locf(avg(v1)) value
3567+
FROM metrics_tstz m1
3568+
WHERE m1.device_id = dev.device_id AND time >= (select min(time) from metrics_tstz m2) AND time < (select max(time) from metrics_tstz m2)
3569+
GROUP BY 1,2) sq ON (true);
3570+
device_id | bucket | value
3571+
-----------+------------------------------+-------
3572+
1 | Mon Jan 01 05:00:00 2018 PST | 0.5
3573+
1 | Mon Jan 01 05:10:00 2018 PST | 0.5
3574+
1 | Mon Jan 01 05:20:00 2018 PST | 0.5
3575+
1 | Mon Jan 01 05:30:00 2018 PST | 0.5
3576+
1 | Mon Jan 01 05:40:00 2018 PST | 0.5
3577+
1 | Mon Jan 01 05:50:00 2018 PST | 0.5
3578+
1 | Mon Jan 01 06:00:00 2018 PST | 0.5
3579+
1 | Mon Jan 01 06:10:00 2018 PST | 0.5
3580+
1 | Mon Jan 01 06:20:00 2018 PST | 0.5
3581+
1 | Mon Jan 01 06:30:00 2018 PST | 0.5
3582+
1 | Mon Jan 01 06:40:00 2018 PST | 0.5
3583+
1 | Mon Jan 01 06:50:00 2018 PST | 0.5
3584+
2 | Mon Jan 01 05:00:00 2018 PST | 0.7
3585+
2 | Mon Jan 01 05:20:00 2018 PST | 0.7
3586+
2 | Mon Jan 01 05:40:00 2018 PST | 0.7
3587+
2 | Mon Jan 01 06:00:00 2018 PST | 0.7
3588+
2 | Mon Jan 01 06:20:00 2018 PST | 0.7
3589+
2 | Mon Jan 01 06:40:00 2018 PST | 0.7
3590+
3 | Mon Jan 01 05:00:00 2018 PST | 0.9
3591+
3 | Mon Jan 01 05:30:00 2018 PST | 0.9
3592+
3 | Mon Jan 01 06:00:00 2018 PST | 0.9
3593+
3 | Mon Jan 01 06:30:00 2018 PST | 0.9
3594+

0 commit comments

Comments
 (0)