mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 18:43:18 +08:00
Fix crash on SELECT WHERE NOT with empty table
Modify table state is not created with an empty tables, which lead to NULL pointer evaluation. Starting from PG12 the planner injects a gating plan node above any node that has pseusdo-constant quals. To fix this, we need to check for such a gating node and handle the case. We could optionally prune the extra node, since there's already such a node below ChunkDispatch. Fixes #1883.
This commit is contained in:
parent
74dcff5807
commit
d0c92dd433
@ -21,6 +21,29 @@
|
||||
#include "chunk_dispatch_plan.h"
|
||||
#include "hypertable_cache.h"
|
||||
|
||||
static PlanState *
|
||||
get_chunk_dispatch_state(ModifyTableState *mtstate, PlanState *substate)
|
||||
{
|
||||
switch (nodeTag(substate))
|
||||
{
|
||||
case T_CustomScanState:
|
||||
{
|
||||
CustomScanState *csstate = castNode(CustomScanState, substate);
|
||||
|
||||
if (strcmp(csstate->methods->CustomName, CHUNK_DISPATCH_STATE_NAME) == 0)
|
||||
return substate;
|
||||
|
||||
break;
|
||||
}
|
||||
case T_ResultState:
|
||||
return get_chunk_dispatch_state(mtstate, castNode(ResultState, substate)->ps.lefttree);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* HypertableInsert (with corresponding executor node) is a plan node that
|
||||
* implements INSERTs for hypertables. It is mostly a wrapper around the
|
||||
@ -36,15 +59,14 @@ static void
|
||||
hypertable_insert_begin(CustomScanState *node, EState *estate, int eflags)
|
||||
{
|
||||
HypertableInsertState *state = (HypertableInsertState *) node;
|
||||
ModifyTableState *mtstate;
|
||||
PlanState *ps;
|
||||
bool PG_USED_FOR_ASSERTS_ONLY found_cdstate = false;
|
||||
int i;
|
||||
|
||||
ps = ExecInitNode(&state->mt->plan, estate, eflags);
|
||||
node->custom_ps = list_make1(ps);
|
||||
|
||||
if (IsA(ps, ModifyTableState))
|
||||
{
|
||||
ModifyTableState *mtstate = (ModifyTableState *) ps;
|
||||
int i;
|
||||
mtstate = castNode(ModifyTableState, ps);
|
||||
|
||||
/*
|
||||
* Find all ChunkDispatchState subnodes and set their parent
|
||||
@ -52,19 +74,18 @@ hypertable_insert_begin(CustomScanState *node, EState *estate, int eflags)
|
||||
*/
|
||||
for (i = 0; i < mtstate->mt_nplans; i++)
|
||||
{
|
||||
if (IsA(mtstate->mt_plans[i], CustomScanState))
|
||||
{
|
||||
CustomScanState *csstate = (CustomScanState *) mtstate->mt_plans[i];
|
||||
ChunkDispatchState *cdstate =
|
||||
(ChunkDispatchState *) get_chunk_dispatch_state(mtstate, mtstate->mt_plans[i]);
|
||||
|
||||
if (strcmp(csstate->methods->CustomName, CHUNK_DISPATCH_STATE_NAME) == 0)
|
||||
if (cdstate)
|
||||
{
|
||||
ChunkDispatchState *cdstate = (ChunkDispatchState *) mtstate->mt_plans[i];
|
||||
|
||||
found_cdstate = true;
|
||||
ts_chunk_dispatch_state_set_parent(cdstate, mtstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that we found at least one ChunkDispatchState node */
|
||||
Assert(found_cdstate);
|
||||
}
|
||||
|
||||
static TupleTableSlot *
|
||||
|
@ -586,3 +586,53 @@ SELECT insert_test(), insert_test(), insert_test();
|
||||
| |
|
||||
(1 row)
|
||||
|
||||
-- test Postgres crashes on INSERT ... SELECT ... WHERE NOT EXISTS with empty table
|
||||
-- https://github.com/timescale/timescaledb/issues/1883
|
||||
CREATE TABLE readings (
|
||||
toe TIMESTAMPTZ NOT NULL,
|
||||
sensor_id INT NOT NULL,
|
||||
value INT NOT NULL
|
||||
);
|
||||
SELECT create_hypertable(
|
||||
'readings',
|
||||
'toe',
|
||||
chunk_time_interval => interval '1 day',
|
||||
if_not_exists => TRUE,
|
||||
migrate_data => TRUE
|
||||
);
|
||||
create_hypertable
|
||||
------------------------
|
||||
(11,public,readings,t)
|
||||
(1 row)
|
||||
|
||||
EXPLAIN (costs off)
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------
|
||||
Custom Scan (HypertableInsert)
|
||||
-> Insert on readings
|
||||
-> Custom Scan (ChunkDispatch)
|
||||
-> Subquery Scan on "*SELECT*"
|
||||
-> Result
|
||||
One-Time Filter: (NOT $0)
|
||||
InitPlan 1 (returns $0)
|
||||
-> Result
|
||||
One-Time Filter: false
|
||||
(9 rows)
|
||||
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
DROP TABLE readings;
|
||||
|
@ -586,3 +586,53 @@ SELECT insert_test(), insert_test(), insert_test();
|
||||
| |
|
||||
(1 row)
|
||||
|
||||
-- test Postgres crashes on INSERT ... SELECT ... WHERE NOT EXISTS with empty table
|
||||
-- https://github.com/timescale/timescaledb/issues/1883
|
||||
CREATE TABLE readings (
|
||||
toe TIMESTAMPTZ NOT NULL,
|
||||
sensor_id INT NOT NULL,
|
||||
value INT NOT NULL
|
||||
);
|
||||
SELECT create_hypertable(
|
||||
'readings',
|
||||
'toe',
|
||||
chunk_time_interval => interval '1 day',
|
||||
if_not_exists => TRUE,
|
||||
migrate_data => TRUE
|
||||
);
|
||||
create_hypertable
|
||||
------------------------
|
||||
(11,public,readings,t)
|
||||
(1 row)
|
||||
|
||||
EXPLAIN (costs off)
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------
|
||||
Custom Scan (HypertableInsert)
|
||||
-> Insert on readings
|
||||
-> Custom Scan (ChunkDispatch)
|
||||
-> Subquery Scan on "*SELECT*"
|
||||
-> Result
|
||||
One-Time Filter: (NOT $0)
|
||||
InitPlan 1 (returns $0)
|
||||
-> Result
|
||||
One-Time Filter: false
|
||||
(9 rows)
|
||||
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
DROP TABLE readings;
|
||||
|
@ -585,3 +585,54 @@ SELECT insert_test(), insert_test(), insert_test();
|
||||
| |
|
||||
(1 row)
|
||||
|
||||
-- test Postgres crashes on INSERT ... SELECT ... WHERE NOT EXISTS with empty table
|
||||
-- https://github.com/timescale/timescaledb/issues/1883
|
||||
CREATE TABLE readings (
|
||||
toe TIMESTAMPTZ NOT NULL,
|
||||
sensor_id INT NOT NULL,
|
||||
value INT NOT NULL
|
||||
);
|
||||
SELECT create_hypertable(
|
||||
'readings',
|
||||
'toe',
|
||||
chunk_time_interval => interval '1 day',
|
||||
if_not_exists => TRUE,
|
||||
migrate_data => TRUE
|
||||
);
|
||||
create_hypertable
|
||||
------------------------
|
||||
(11,public,readings,t)
|
||||
(1 row)
|
||||
|
||||
EXPLAIN (costs off)
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------
|
||||
Custom Scan (HypertableInsert)
|
||||
InitPlan 1 (returns $0)
|
||||
-> Result
|
||||
One-Time Filter: false
|
||||
-> Insert on readings
|
||||
-> Result
|
||||
One-Time Filter: (NOT $0)
|
||||
-> Custom Scan (ChunkDispatch)
|
||||
-> Result
|
||||
One-Time Filter: (NOT $0)
|
||||
(10 rows)
|
||||
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
DROP TABLE readings;
|
||||
|
@ -586,3 +586,53 @@ SELECT insert_test(), insert_test(), insert_test();
|
||||
| |
|
||||
(1 row)
|
||||
|
||||
-- test Postgres crashes on INSERT ... SELECT ... WHERE NOT EXISTS with empty table
|
||||
-- https://github.com/timescale/timescaledb/issues/1883
|
||||
CREATE TABLE readings (
|
||||
toe TIMESTAMPTZ NOT NULL,
|
||||
sensor_id INT NOT NULL,
|
||||
value INT NOT NULL
|
||||
);
|
||||
SELECT create_hypertable(
|
||||
'readings',
|
||||
'toe',
|
||||
chunk_time_interval => interval '1 day',
|
||||
if_not_exists => TRUE,
|
||||
migrate_data => TRUE
|
||||
);
|
||||
create_hypertable
|
||||
------------------------
|
||||
(11,public,readings,t)
|
||||
(1 row)
|
||||
|
||||
EXPLAIN (costs off)
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------
|
||||
Custom Scan (HypertableInsert)
|
||||
-> Insert on readings
|
||||
-> Custom Scan (ChunkDispatch)
|
||||
-> Subquery Scan on "*SELECT*"
|
||||
-> Result
|
||||
One-Time Filter: (NOT $0)
|
||||
InitPlan 1 (returns $0)
|
||||
-> Result
|
||||
One-Time Filter: false
|
||||
(9 rows)
|
||||
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
DROP TABLE readings;
|
||||
|
@ -148,4 +148,35 @@ $$;
|
||||
|
||||
SELECT insert_test(), insert_test(), insert_test();
|
||||
|
||||
|
||||
-- test Postgres crashes on INSERT ... SELECT ... WHERE NOT EXISTS with empty table
|
||||
-- https://github.com/timescale/timescaledb/issues/1883
|
||||
CREATE TABLE readings (
|
||||
toe TIMESTAMPTZ NOT NULL,
|
||||
sensor_id INT NOT NULL,
|
||||
value INT NOT NULL
|
||||
);
|
||||
SELECT create_hypertable(
|
||||
'readings',
|
||||
'toe',
|
||||
chunk_time_interval => interval '1 day',
|
||||
if_not_exists => TRUE,
|
||||
migrate_data => TRUE
|
||||
);
|
||||
EXPLAIN (costs off)
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
INSERT INTO readings
|
||||
SELECT '2020-05-09 10:34:35.296288+00', 1, 0
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM readings
|
||||
WHERE sensor_id = 1
|
||||
AND toe = '2020-05-09 10:34:35.296288+00'
|
||||
);
|
||||
DROP TABLE readings;
|
||||
|
Loading…
x
Reference in New Issue
Block a user