Merge fe6a09e5f7 into b8de2801c7
This commit is contained in:
commit
1385af4e21
6 changed files with 147 additions and 12 deletions
|
|
@ -896,10 +896,6 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("TABLESAMPLE clause is not supported on incrementally maintainable materialized view")));
|
errmsg("TABLESAMPLE clause is not supported on incrementally maintainable materialized view")));
|
||||||
|
|
||||||
if (rte->relkind == RELKIND_PARTITIONED_TABLE)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("partitioned table is not supported on incrementally maintainable materialized view")));
|
|
||||||
|
|
||||||
if (rte->relkind == RELKIND_RELATION && has_superclass(rte->relid))
|
if (rte->relkind == RELKIND_RELATION && has_superclass(rte->relid))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
|
|
||||||
|
|
@ -116,3 +116,33 @@ ERROR: relation "mv_not_existing" does not exist
|
||||||
-- Try to refresh a normal table -- error
|
-- Try to refresh a normal table -- error
|
||||||
SELECT refresh_immv('t', true);
|
SELECT refresh_immv('t', true);
|
||||||
ERROR: "t" is not an IMMV
|
ERROR: "t" is not an IMMV
|
||||||
|
-- Create partitioned table
|
||||||
|
CREATE TABLE foo (id integer) PARTITION BY RANGE(id);
|
||||||
|
CREATE TABLE foo_default PARTITION OF foo DEFAULT;
|
||||||
|
INSERT INTO foo VALUES (1), (2), (3);
|
||||||
|
SELECT create_immv('foo_mv', 'SELECT COUNT(*) as count FROM foo');
|
||||||
|
create_immv
|
||||||
|
-------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT count FROM foo_mv;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
3
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
ALTER TABLE foo DETACH PARTITION foo_default;
|
||||||
|
SELECT count FROM foo_mv;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
ALTER TABLE foo ATTACH PARTITION foo_default DEFAULT;
|
||||||
|
SELECT count FROM foo_mv;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
3
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
|
|
||||||
57
matview.c
57
matview.c
|
|
@ -41,6 +41,7 @@
|
||||||
#include "rewrite/rewriteManip.h"
|
#include "rewrite/rewriteManip.h"
|
||||||
#include "rewrite/rowsecurity.h"
|
#include "rewrite/rowsecurity.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
|
#include "tcop/deparse_utility.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
|
|
@ -220,6 +221,7 @@ static void mv_BuildQueryKey(MV_QueryKey *key, Oid matview_id, int32 query_type)
|
||||||
static void clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort);
|
static void clean_up_IVM_hash_entry(MV_TriggerHashEntry *entry, bool is_abort);
|
||||||
|
|
||||||
/* SQL callable functions */
|
/* SQL callable functions */
|
||||||
|
PG_FUNCTION_INFO_V1(changes_partitions);
|
||||||
PG_FUNCTION_INFO_V1(IVM_immediate_before);
|
PG_FUNCTION_INFO_V1(IVM_immediate_before);
|
||||||
PG_FUNCTION_INFO_V1(IVM_immediate_maintenance);
|
PG_FUNCTION_INFO_V1(IVM_immediate_maintenance);
|
||||||
PG_FUNCTION_INFO_V1(ivm_visible_in_prestate);
|
PG_FUNCTION_INFO_V1(ivm_visible_in_prestate);
|
||||||
|
|
@ -683,12 +685,59 @@ tuplestore_copy(Tuplestorestate *tuplestore, Relation rel)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IVM_immediate_before
|
* changes_partitions
|
||||||
*
|
*
|
||||||
* IVM trigger function invoked before base table is modified. If this is
|
* Accepts a parsed ALTER TABLE command (from pg_event_trigger_ddl_commands),
|
||||||
* invoked firstly in the same statement, we save the transaction id and the
|
* returning whether that ALTER TABLE command contains subcommands related to
|
||||||
* command id at that time.
|
* changing partitions (i.e. ATTACH or DETACH PARTITION).
|
||||||
*/
|
*/
|
||||||
|
Datum
|
||||||
|
changes_partitions(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
CollectedCommand *cmd = (CollectedCommand *) PG_GETARG_POINTER(0);
|
||||||
|
ListCell *subcmdCell = NULL;
|
||||||
|
|
||||||
|
CollectedATSubcmd *collAlterSubcmd = NULL;
|
||||||
|
AlterTableCmd *alterCmd = NULL;
|
||||||
|
|
||||||
|
Oid newPartRelid = InvalidOid;
|
||||||
|
Oid oldPartRelid = InvalidOid;
|
||||||
|
|
||||||
|
/* this function is intended for ALTER TABLE only */
|
||||||
|
if (cmd->type != SCT_AlterTable)
|
||||||
|
{
|
||||||
|
elog(ERROR, "command is not ALTER TABLE");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* expect at least one sub-command */
|
||||||
|
subcmdCell = list_head(cmd->d.alterTable.subcmds);
|
||||||
|
if (subcmdCell == NULL)
|
||||||
|
{
|
||||||
|
elog(ERROR, "empty alter table subcommand list");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This saves the OIDs of the affected partitions, for later use
|
||||||
|
* in an incremental approach.
|
||||||
|
*/
|
||||||
|
collAlterSubcmd = lfirst(subcmdCell);
|
||||||
|
alterCmd = castNode(AlterTableCmd, collAlterSubcmd->parsetree);
|
||||||
|
if (alterCmd->subtype == AT_AttachPartition)
|
||||||
|
{
|
||||||
|
newPartRelid = collAlterSubcmd->address.objectId;
|
||||||
|
}
|
||||||
|
else if (alterCmd->subtype == AT_DetachPartition)
|
||||||
|
{
|
||||||
|
oldPartRelid = collAlterSubcmd->address.objectId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BoolGetDatum(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BoolGetDatum(true);
|
||||||
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
IVM_immediate_before(PG_FUNCTION_ARGS)
|
IVM_immediate_before(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,22 @@ SELECT pg_catalog.pg_extension_config_dump('pg_catalog.pg_ivm_immv', '');
|
||||||
|
|
||||||
-- functions
|
-- functions
|
||||||
|
|
||||||
|
CREATE FUNCTION changes_partitions(pg_ddl_command)
|
||||||
|
RETURNS boolean
|
||||||
|
IMMUTABLE
|
||||||
|
STRICT
|
||||||
|
AS 'MODULE_PATHNAME', 'changes_partitions'
|
||||||
|
LANGUAGE C;
|
||||||
|
|
||||||
|
-- CREATE FUNCTION get_command_type(text, text, pg_ddl_command, text)
|
||||||
|
-- RETURNS void
|
||||||
|
-- IMMUTABLE
|
||||||
|
-- STRICT
|
||||||
|
-- AS 'MODULE_PATHNAME', 'get_command_type'
|
||||||
|
-- LANGUAGE C;
|
||||||
|
|
||||||
CREATE FUNCTION create_immv(text, text)
|
CREATE FUNCTION create_immv(text, text)
|
||||||
RETURNS bigint
|
RETURNS bigint
|
||||||
STRICT
|
STRICT
|
||||||
AS 'MODULE_PATHNAME', 'create_immv'
|
AS 'MODULE_PATHNAME', 'create_immv'
|
||||||
LANGUAGE C;
|
LANGUAGE C;
|
||||||
|
|
@ -26,17 +40,17 @@ LANGUAGE C;
|
||||||
-- trigger functions
|
-- trigger functions
|
||||||
|
|
||||||
CREATE FUNCTION "IVM_immediate_before"()
|
CREATE FUNCTION "IVM_immediate_before"()
|
||||||
RETURNS trigger
|
RETURNS trigger
|
||||||
AS 'MODULE_PATHNAME', 'IVM_immediate_before'
|
AS 'MODULE_PATHNAME', 'IVM_immediate_before'
|
||||||
LANGUAGE C;
|
LANGUAGE C;
|
||||||
|
|
||||||
CREATE FUNCTION "IVM_immediate_maintenance"()
|
CREATE FUNCTION "IVM_immediate_maintenance"()
|
||||||
RETURNS trigger
|
RETURNS trigger
|
||||||
AS 'MODULE_PATHNAME', 'IVM_immediate_maintenance'
|
AS 'MODULE_PATHNAME', 'IVM_immediate_maintenance'
|
||||||
LANGUAGE C;
|
LANGUAGE C;
|
||||||
|
|
||||||
CREATE FUNCTION "IVM_prevent_immv_change"()
|
CREATE FUNCTION "IVM_prevent_immv_change"()
|
||||||
RETURNS trigger
|
RETURNS trigger
|
||||||
AS 'MODULE_PATHNAME', 'IVM_prevent_immv_change'
|
AS 'MODULE_PATHNAME', 'IVM_prevent_immv_change'
|
||||||
LANGUAGE C;
|
LANGUAGE C;
|
||||||
|
|
||||||
|
|
@ -64,3 +78,33 @@ $$ LANGUAGE plpgsql;
|
||||||
CREATE EVENT TRIGGER pg_ivm_sql_drop_trigger
|
CREATE EVENT TRIGGER pg_ivm_sql_drop_trigger
|
||||||
ON sql_drop
|
ON sql_drop
|
||||||
EXECUTE PROCEDURE pg_catalog.pg_ivm_sql_drop_trigger_func();
|
EXECUTE PROCEDURE pg_catalog.pg_ivm_sql_drop_trigger_func();
|
||||||
|
|
||||||
|
-- Process ALTER TABLE, specifically ATTACH/DETACH PARTITION
|
||||||
|
-- TODO: Get incremental update working
|
||||||
|
CREATE OR REPLACE FUNCTION ivm_immediate_event()
|
||||||
|
RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $function$
|
||||||
|
DECLARE
|
||||||
|
r record;
|
||||||
|
BEGIN
|
||||||
|
FOR r IN SELECT * FROM pg_event_trigger_ddl_commands()
|
||||||
|
LOOP
|
||||||
|
IF changes_partitions(r.command) THEN
|
||||||
|
PERFORM refresh_immv(
|
||||||
|
convert_from(
|
||||||
|
substring(tgargs FOR (position('\x00'::bytea in tgargs)-1)),
|
||||||
|
'SQL_ASCII'
|
||||||
|
)::oid::regclass::text,
|
||||||
|
true)
|
||||||
|
FROM pg_trigger
|
||||||
|
WHERE tgfoid='"IVM_immediate_maintenance"'::regproc AND tgtype=4;
|
||||||
|
END IF;
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$function$;
|
||||||
|
|
||||||
|
-- Run on any ALTER TABLE
|
||||||
|
CREATE EVENT TRIGGER IVM_trigger_event
|
||||||
|
ON ddl_command_end WHEN TAG IN ('ALTER TABLE')
|
||||||
|
EXECUTE PROCEDURE ivm_immediate_event();
|
||||||
|
|
|
||||||
1
pg_ivm.h
1
pg_ivm.h
|
|
@ -51,6 +51,7 @@ extern ObjectAddress RefreshImmvByOid(Oid matviewOid, bool skipData,
|
||||||
const char *queryString, QueryCompletion *qc);
|
const char *queryString, QueryCompletion *qc);
|
||||||
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
||||||
extern Query *get_immv_query(Relation matviewRel);
|
extern Query *get_immv_query(Relation matviewRel);
|
||||||
|
extern Datum changes_partitions(PG_FUNCTION_ARGS);
|
||||||
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
||||||
extern Datum IVM_immediate_maintenance(PG_FUNCTION_ARGS);
|
extern Datum IVM_immediate_maintenance(PG_FUNCTION_ARGS);
|
||||||
extern Query* rewrite_query_for_exists_subquery(Query *query);
|
extern Query* rewrite_query_for_exists_subquery(Query *query);
|
||||||
|
|
|
||||||
|
|
@ -37,3 +37,18 @@ SELECT refresh_immv('mv_not_existing', true);
|
||||||
|
|
||||||
-- Try to refresh a normal table -- error
|
-- Try to refresh a normal table -- error
|
||||||
SELECT refresh_immv('t', true);
|
SELECT refresh_immv('t', true);
|
||||||
|
|
||||||
|
-- Create partitioned table
|
||||||
|
CREATE TABLE foo (id integer) PARTITION BY RANGE(id);
|
||||||
|
CREATE TABLE foo_default PARTITION OF foo DEFAULT;
|
||||||
|
|
||||||
|
INSERT INTO foo VALUES (1), (2), (3);
|
||||||
|
|
||||||
|
SELECT create_immv('foo_mv', 'SELECT COUNT(*) as count FROM foo');
|
||||||
|
SELECT count FROM foo_mv;
|
||||||
|
|
||||||
|
ALTER TABLE foo DETACH PARTITION foo_default;
|
||||||
|
SELECT count FROM foo_mv;
|
||||||
|
|
||||||
|
ALTER TABLE foo ATTACH PARTITION foo_default DEFAULT;
|
||||||
|
SELECT count FROM foo_mv;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue