CIMV prototype with basic testing

pull/4302/head
Benjamin Satzger 2020-10-27 16:53:18 +00:00
parent 5fcddfa2c6
commit 548a741c91
18 changed files with 4622 additions and 26 deletions

View File

@ -18,7 +18,7 @@ generated_downgrade_sql_files += $(patsubst %,$(citus_abs_srcdir)/build/sql/%,$(
DATA_built = $(generated_sql_files) DATA_built = $(generated_sql_files)
# directories with source files # directories with source files
SUBDIRS = . commands connection ddl deparser executor metadata operations planner progress relay safeclib test transaction utils worker SUBDIRS = . commands connection ddl deparser executor metadata operations planner progress relay safeclib test transaction utils worker cimv
# Symlinks are not copied over to the build directory if a separete build # Symlinks are not copied over to the build directory if a separete build
# directory is used during configure (such as on CI) # directory is used during configure (such as on CI)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,245 @@
#include "postgres.h"
#include "catalog/dependency.h"
#include "catalog/objectaddress.h"
#include "catalog/pg_class.h"
#include "distributed/listutils.h"
#include "distributed/metadata_cache.h"
#include "distributed/pg_cimv.h"
#include "executor/spi.h"
#include "nodes/parsenodes.h"
#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "distributed/cimv.h"
static void DropCimv(Form_pg_cimv formCimv, DropBehavior behavior);
static void DropDmlTriggers(Form_pg_cimv cimv);
static void DropCronJob(Form_pg_cimv cimv);
extern void
ProcessDropMaterializedViewStmt(DropStmt *stmt)
{
if (stmt->removeType != OBJECT_MATVIEW)
{
return;
}
List *viewNameList = NULL;
List *cimvObjects = NIL;
List *formCimvs = NIL;
Form_pg_cimv formCimv;
bool hasCimv = false;
bool hasNonCimv = false;
foreach_ptr(viewNameList, stmt->objects)
{
RangeVar *viewRangeVar = makeRangeVarFromNameList(viewNameList);
Oid relationId = RangeVarGetRelid(viewRangeVar, NoLock, true);
if (relationId == InvalidOid)
{
hasNonCimv = true;
continue;
}
formCimv = LookupCimvFromCatalog(relationId, true);
if (formCimv == NULL)
{
hasNonCimv = true;
continue;
}
hasCimv = true;
cimvObjects = lappend(cimvObjects, list_make2(makeString(get_namespace_name(
get_rel_namespace(
formCimv->
mattable))),
makeString(get_rel_name(
formCimv
->
mattable))));
formCimvs = lappend(formCimvs, formCimv);
}
if (hasCimv && hasNonCimv)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg(
"cannot drop regular and Citus materialized views with single command")));
}
if (hasCimv)
{
foreach_ptr(formCimv, formCimvs)
{
DropCimv(formCimv, stmt->behavior);
}
stmt->removeType = OBJECT_TABLE;
stmt->objects = cimvObjects;
}
}
extern void
ProcessDropViewStmt(DropStmt *stmt)
{
if (stmt->removeType != OBJECT_VIEW)
{
return;
}
List *viewNameList = NULL;
foreach_ptr(viewNameList, stmt->objects)
{
RangeVar *viewRangeVar = makeRangeVarFromNameList(viewNameList);
Oid relationId = RangeVarGetRelid(viewRangeVar, NoLock, true);
if (relationId == InvalidOid)
{
continue;
}
Form_pg_cimv formCimv = LookupCimvFromCatalog(relationId, true);
if (formCimv != NULL)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("DROP VIEW not supported for %s",
viewRangeVar->relname),
errhint("use DROP MATERIALIZED VIEW")));
}
}
}
static void
DropCimv(Form_pg_cimv formCimv, DropBehavior behavior)
{
ObjectAddress matTableAddress;
matTableAddress.classId = RelationRelationId;
matTableAddress.objectId = formCimv->mattable;
matTableAddress.objectSubId = 0;
ObjectAddress userViewAddress;
userViewAddress.classId = RelationRelationId;
userViewAddress.objectId = formCimv->userview;
userViewAddress.objectSubId = 0;
ObjectAddress refreshViewAddress;
refreshViewAddress.classId = RelationRelationId;
refreshViewAddress.objectId = formCimv->refreshview;
refreshViewAddress.objectSubId = 0;
ObjectAddress landingTableAddress;
landingTableAddress.classId = RelationRelationId;
landingTableAddress.objectId = formCimv->landingtable;
landingTableAddress.objectSubId = 0;
if (SPI_connect() != SPI_OK_CONNECT)
{
elog(ERROR, "SPI_connect failed");
}
DropCronJob(formCimv);
DropDmlTriggers(formCimv);
/* Lock */
if (OidIsValid(matTableAddress.objectId))
{
AcquireDeletionLock(&matTableAddress, 0);
}
if (OidIsValid(userViewAddress.objectId))
{
AcquireDeletionLock(&userViewAddress, 0);
}
if (OidIsValid(refreshViewAddress.objectId))
{
AcquireDeletionLock(&refreshViewAddress, 0);
}
if (OidIsValid(landingTableAddress.objectId))
{
AcquireDeletionLock(&landingTableAddress, 0);
}
/* Drop views */
if (OidIsValid(userViewAddress.objectId))
{
performDeletion(&userViewAddress, behavior, 0);
}
if (OidIsValid(refreshViewAddress.objectId))
{
performDeletion(&refreshViewAddress, behavior, 0);
}
/* Drop landing table */
if (OidIsValid(landingTableAddress.objectId))
{
performDeletion(&landingTableAddress, behavior, 0);
}
DeletePgCimvRow(userViewAddress.objectId);
/* Close SPI context. */
if (SPI_finish() != SPI_OK_FINISH)
{
elog(ERROR, "SPI_finish failed");
}
}
static void
DropDmlTriggers(Form_pg_cimv cimv)
{
StringInfoData querybuf;
initStringInfo(&querybuf);
appendStringInfo(&querybuf,
"DROP FUNCTION %s.%s CASCADE;",
quote_identifier(NameStr(cimv->triggerfnnamespace)),
quote_identifier(NameStr(cimv->triggerfnname)));
if (SPI_execute(querybuf.data, false, 0) != SPI_OK_UTILITY)
{
elog(ERROR, "SPI_exec failed: %s", querybuf.data);
}
pfree(querybuf.data);
}
static void
DropCronJob(Form_pg_cimv cimv)
{
if (cimv->jobid == 0)
{
return;
}
StringInfoData querybuf;
initStringInfo(&querybuf);
appendStringInfo(&querybuf,
"SELECT * FROM cron.unschedule(" INT64_FORMAT ");",
cimv->jobid);
int spiResult = SPI_execute(querybuf.data, false, 0);
if (spiResult != SPI_OK_SELECT)
{
elog(ERROR, "SPI_exec failed: %s", querybuf.data);
}
pfree(querybuf.data);
}

View File

@ -0,0 +1,193 @@
#include "postgres.h"
#include "catalog/dependency.h"
#include "catalog/objectaddress.h"
#include "catalog/pg_class.h"
#include "distributed/listutils.h"
#include "distributed/metadata_cache.h"
#include "distributed/pg_cimv.h"
#include "executor/spi.h"
#include "nodes/parsenodes.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/snapmgr.h"
#include "distributed/cimv.h"
static void SpiExecuteSnapshot(StringInfo query, Snapshot snapshot, int expectedResult);
static void SpiExecute(StringInfo query, int expectedResult);
bool
ProcessRefreshMaterializedViewStmt(RefreshMatViewStmt *stmt)
{
Oid relationId = RangeVarGetRelid(stmt->relation, NoLock, true);
if (relationId == InvalidOid)
{
return false;
}
Form_pg_cimv formCimv = LookupCimvFromCatalog(relationId, true);
if (formCimv == NULL)
{
return false;
}
RefreshCimv(formCimv, stmt->skipData, false);
return true;
}
void
RefreshCimv(Form_pg_cimv formCimv, bool skipData, bool isCreate)
{
StringInfoData querybuf;
initStringInfo(&querybuf);
if (SPI_connect_ext(SPI_OPT_NONATOMIC) != SPI_OK_CONNECT)
{
elog(ERROR, "SPI_connect failed");
}
const char *matTableSchemaName = get_namespace_name(get_rel_namespace(
formCimv->mattable));
const char *matTableName = get_rel_name(formCimv->mattable);
matTableSchemaName = quote_identifier(matTableSchemaName);
matTableName = quote_identifier(matTableName);
const char *landingTableSchemaName = NULL;
const char *landingTableName = NULL;
if (formCimv->landingtable)
{
landingTableSchemaName = get_namespace_name(get_rel_namespace(
formCimv->landingtable));
landingTableName = get_rel_name(formCimv->landingtable);
landingTableSchemaName = quote_identifier(landingTableSchemaName);
landingTableName = quote_identifier(landingTableName);
}
if (skipData)
{
if (formCimv->landingtable)
{
appendStringInfo(&querybuf,
"TRUNCATE TABLE %s.%s",
landingTableSchemaName,
landingTableName);
SpiExecute(&querybuf, SPI_OK_UTILITY);
resetStringInfo(&querybuf);
}
appendStringInfo(&querybuf,
"TRUNCATE TABLE %s.%s",
matTableSchemaName,
matTableName);
SpiExecute(&querybuf, SPI_OK_UTILITY);
resetStringInfo(&querybuf);
}
else
{
const char *refreshViewSchemaName = get_namespace_name(get_rel_namespace(
formCimv->refreshview));
const char *refreshViewName = get_rel_name(formCimv->refreshview);
refreshViewSchemaName = quote_identifier(refreshViewSchemaName);
refreshViewName = quote_identifier(refreshViewName);
if (isCreate)
{
/* better: SPI_commit_and_chain(); */
SPI_commit();
SPI_start_transaction();
/* TODO: cleanup if this fails */
appendStringInfo(&querybuf,
"INSERT INTO %s.%s "
"SELECT * FROM %s.%s",
matTableSchemaName,
matTableName,
refreshViewSchemaName,
refreshViewName);
if (SPI_execute(querybuf.data, false, 0) != SPI_OK_INSERT)
{
elog(ERROR, "SPI_exec failed: %s", querybuf.data);
}
}
else
{
Snapshot snapshot = GetLatestSnapshot();
/* TODO: DELETE only if !isCreate */
appendStringInfo(&querybuf,
"DELETE FROM %s.%s",
matTableSchemaName,
matTableName);
SpiExecuteSnapshot(&querybuf, snapshot, SPI_OK_DELETE);
resetStringInfo(&querybuf);
appendStringInfo(&querybuf,
"INSERT INTO %s.%s "
"SELECT * FROM %s.%s",
matTableSchemaName,
matTableName,
refreshViewSchemaName,
refreshViewName);
SpiExecuteSnapshot(&querybuf, snapshot, SPI_OK_INSERT);
resetStringInfo(&querybuf);
if (formCimv->landingtable != InvalidOid)
{
/* TODO: DELETE only if !isCreate */
appendStringInfo(&querybuf,
"DELETE FROM %s.%s",
landingTableSchemaName,
landingTableName);
SpiExecuteSnapshot(&querybuf, snapshot, SPI_OK_DELETE);
resetStringInfo(&querybuf);
}
}
}
/* Close SPI context. */
if (SPI_finish() != SPI_OK_FINISH)
{
elog(ERROR, "SPI_finish failed");
}
}
static void
SpiExecuteSnapshot(StringInfo query, Snapshot snapshot, int expectedResult)
{
SPIPlanPtr qplan = SPI_prepare(query->data, 0, NULL);
if (qplan == NULL)
{
elog(ERROR, "SPI_prepare returned %s for %s",
SPI_result_code_string(SPI_result), query->data);
}
int spi_result = SPI_execute_snapshot(qplan,
NULL, NULL,
snapshot,
InvalidSnapshot,
false, false, 0);
if (spi_result != expectedResult)
{
elog(ERROR, "SPI_exec failed: %s", query->data);
}
}
static void
SpiExecute(StringInfo query, int expectedResult)
{
int spi_result = SPI_execute(query->data, false, 0);
if (spi_result != expectedResult)
{
elog(ERROR, "SPI_exec failed: %s", query->data);
}
}

View File

@ -59,6 +59,7 @@
#include "distributed/transmit.h" #include "distributed/transmit.h"
#include "distributed/version_compat.h" #include "distributed/version_compat.h"
#include "distributed/worker_transaction.h" #include "distributed/worker_transaction.h"
#include "distributed/cimv.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
@ -457,6 +458,35 @@ multi_ProcessUtility(PlannedStmt *pstmt,
} }
} }
bool continueProcessing = true;
if (IsA(parsetree, CreateTableAsStmt))
{
continueProcessing = !ProcessCreateMaterializedViewStmt((const
CreateTableAsStmt *)
parsetree, queryString,
pstmt);
}
if (IsA(parsetree, RefreshMatViewStmt))
{
continueProcessing = !ProcessRefreshMaterializedViewStmt(
(RefreshMatViewStmt *) parsetree);
}
if (IsA(parsetree, DropStmt))
{
DropStmt *dropStatement = (DropStmt *) parsetree;
if (dropStatement->removeType == OBJECT_MATVIEW)
{
ProcessDropMaterializedViewStmt(dropStatement);
}
else if (dropStatement->removeType == OBJECT_VIEW)
{
ProcessDropViewStmt(dropStatement);
}
}
if (IsDropCitusExtensionStmt(parsetree)) if (IsDropCitusExtensionStmt(parsetree))
{ {
StopMaintenanceDaemon(MyDatabaseId); StopMaintenanceDaemon(MyDatabaseId);
@ -483,8 +513,11 @@ multi_ProcessUtility(PlannedStmt *pstmt,
citusCanBeUpdatedToAvailableVersion = !InstalledAndAvailableVersionsSame(); citusCanBeUpdatedToAvailableVersion = !InstalledAndAvailableVersionsSame();
} }
standard_ProcessUtility(pstmt, queryString, context, if (continueProcessing)
params, queryEnv, dest, completionTag); {
standard_ProcessUtility(pstmt, queryString, context,
params, queryEnv, dest, completionTag);
}
/* /*
* if we are running ALTER EXTENSION citus UPDATE (to "<version>") command, we may need * if we are running ALTER EXTENSION citus UPDATE (to "<version>") command, we may need

View File

@ -33,6 +33,7 @@
#include "commands/trigger.h" #include "commands/trigger.h"
#include "distributed/colocation_utils.h" #include "distributed/colocation_utils.h"
#include "distributed/connection_management.h" #include "distributed/connection_management.h"
#include "distributed/cimv.h"
#include "distributed/citus_ruleutils.h" #include "distributed/citus_ruleutils.h"
#include "distributed/function_utils.h" #include "distributed/function_utils.h"
#include "distributed/foreign_key_relationship.h" #include "distributed/foreign_key_relationship.h"
@ -140,6 +141,8 @@ typedef struct MetadataCacheData
Oid distColocationRelationId; Oid distColocationRelationId;
Oid distColocationConfigurationIndexId; Oid distColocationConfigurationIndexId;
Oid distPartitionRelationId; Oid distPartitionRelationId;
Oid pgCimvId;
Oid pgCimvIndexId;
Oid distPartitionLogicalRelidIndexId; Oid distPartitionLogicalRelidIndexId;
Oid distPartitionColocationidIndexId; Oid distPartitionColocationidIndexId;
Oid distShardLogicalRelidIndexId; Oid distShardLogicalRelidIndexId;
@ -2118,6 +2121,28 @@ DistPartitionRelationId(void)
} }
/* return oid of pg_cimv relation */
Oid
PgCimvId(void)
{
CachedRelationLookup("pg_cimv",
&MetadataCache.pgCimvId);
return MetadataCache.pgCimvId;
}
/* return oid of pg_cimv_pkey index */
Oid
PgCimvIndexId(void)
{
CachedRelationLookup("pg_cimv_pkey",
&MetadataCache.pgCimvIndexId);
return MetadataCache.pgCimvIndexId;
}
/* return oid of pg_dist_partition_logical_relid_index index */ /* return oid of pg_dist_partition_logical_relid_index index */
Oid Oid
DistPartitionLogicalRelidIndexId(void) DistPartitionLogicalRelidIndexId(void)

View File

@ -46,6 +46,7 @@
#include "distributed/pg_dist_partition.h" #include "distributed/pg_dist_partition.h"
#include "distributed/pg_dist_shard.h" #include "distributed/pg_dist_shard.h"
#include "distributed/pg_dist_placement.h" #include "distributed/pg_dist_placement.h"
#include "distributed/pg_cimv.h"
#include "distributed/reference_table_utils.h" #include "distributed/reference_table_utils.h"
#include "distributed/relay_utility.h" #include "distributed/relay_utility.h"
#include "distributed/resource_lock.h" #include "distributed/resource_lock.h"
@ -1031,6 +1032,110 @@ InsertIntoPgDistPartition(Oid relationId, char distributionMethod,
} }
/*
* InsertIntoPgCimv inserts a new tuple into pg_cimv.
*/
void
InsertIntoPgCimv(Form_pg_cimv cimv)
{
Datum newValues[Natts_pg_cimv];
bool newNulls[Natts_pg_cimv];
/* open system catalog and insert new tuple */
Relation pgCimv = table_open(PgCimvId(), RowExclusiveLock);
/* form new tuple for pg_cimv */
memset(newValues, 0, sizeof(newValues));
memset(newNulls, false, sizeof(newNulls));
newValues[Anum_pg_cimv_userview - 1] = ObjectIdGetDatum(cimv->userview);
newValues[Anum_pg_cimv_basetable - 1] = ObjectIdGetDatum(cimv->basetable);
newValues[Anum_pg_cimv_mattable - 1] = ObjectIdGetDatum(cimv->mattable);
newValues[Anum_pg_cimv_refreshview - 1] = ObjectIdGetDatum(cimv->refreshview);
newValues[Anum_pg_cimv_triggernamespace - 1] = NameGetDatum(
&cimv->triggerfnnamespace);
newValues[Anum_pg_cimv_triggername - 1] = NameGetDatum(&cimv->triggerfnname);
newValues[Anum_pg_cimv_landingtable - 1] = ObjectIdGetDatum(cimv->landingtable);
newValues[Anum_pg_cimv_jobid - 1] = Int64GetDatum(cimv->jobid);
HeapTuple newTuple = heap_form_tuple(RelationGetDescr(pgCimv), newValues,
newNulls);
/* finally insert tuple, build index entries & register cache invalidation */
CatalogTupleInsert(pgCimv, newTuple);
CommandCounterIncrement();
table_close(pgCimv, NoLock);
}
void
DeletePgCimvRow(Oid userViewId)
{
ScanKeyData scanKey[1];
int scanKeyCount = 1;
Relation pgCimv = table_open(PgCimvId(), RowExclusiveLock);
ScanKeyInit(&scanKey[0], Anum_pg_cimv_userview,
BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(userViewId));
SysScanDesc scanDescriptor = systable_beginscan(pgCimv, InvalidOid, false,
NULL,
scanKeyCount, scanKey);
HeapTuple heapTuple = systable_getnext(scanDescriptor);
if (!HeapTupleIsValid(heapTuple))
{
ereport(ERROR, (errmsg("could not find valid entry for cimv %d",
userViewId)));
}
simple_heap_delete(pgCimv, &heapTuple->t_self);
systable_endscan(scanDescriptor);
/* increment the counter so that next command can see the row */
CommandCounterIncrement();
table_close(pgCimv, NoLock);
}
Form_pg_cimv
LookupCimvFromCatalog(Oid userViewId, bool missingOk)
{
ScanKeyData scanKey[1];
int scanKeyCount = 1;
Form_pg_cimv cimvForm = NULL;
Relation pgCimv = table_open(PgCimvId(), AccessShareLock);
ScanKeyInit(&scanKey[0], Anum_pg_cimv_userview,
BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(userViewId));
SysScanDesc scanDescriptor = systable_beginscan(pgCimv,
PgCimvIndexId(), true,
NULL, scanKeyCount, scanKey);
HeapTuple heapTuple = systable_getnext(scanDescriptor);
if (!HeapTupleIsValid(heapTuple) && !missingOk)
{
ereport(ERROR, (errmsg("could not find valid entry for view %u", userViewId)));
}
if (HeapTupleIsValid(heapTuple))
{
cimvForm = (Form_pg_cimv) GETSTRUCT(heapTuple);
}
systable_endscan(scanDescriptor);
table_close(pgCimv, NoLock);
return cimvForm;
}
/* /*
* RecordDistributedRelationDependencies creates the dependency entries * RecordDistributedRelationDependencies creates the dependency entries
* necessary for a distributed relation in addition to the preexisting ones * necessary for a distributed relation in addition to the preexisting ones

View File

@ -20,4 +20,82 @@ DROP TRIGGER dist_poolinfo_task_tracker_cache_invalidate ON pg_catalog.pg_dist_p
DROP FUNCTION task_tracker_conninfo_cache_invalidate(); DROP FUNCTION task_tracker_conninfo_cache_invalidate();
DROP FUNCTION master_drop_sequences(text[]); DROP FUNCTION master_drop_sequences(text[]);
CREATE FUNCTION pg_catalog.partial_agg_sfunc(internal, oid, anyelement, int)
RETURNS internal
AS 'MODULE_PATHNAME'
LANGUAGE C PARALLEL SAFE;
CREATE FUNCTION pg_catalog.partial_agg_ffunc(internal)
RETURNS bytea
AS 'MODULE_PATHNAME'
LANGUAGE C PARALLEL SAFE;
CREATE AGGREGATE pg_catalog.partial_agg(oid, anyelement, int) (
STYPE = internal,
SFUNC = pg_catalog.partial_agg_sfunc,
FINALFUNC = pg_catalog.partial_agg_ffunc
);
CREATE FUNCTION pg_catalog.combine_agg_sfunc(internal, oid, bytea, anyelement)
RETURNS internal
AS 'MODULE_PATHNAME'
LANGUAGE C PARALLEL SAFE;
CREATE FUNCTION pg_catalog.combine_agg_sfunc(internal, oid, bytea)
RETURNS internal
AS 'MODULE_PATHNAME'
LANGUAGE C PARALLEL SAFE;
CREATE FUNCTION pg_catalog.combine_agg_ffunc(internal, oid, bytea, anyelement)
RETURNS anyelement
AS 'MODULE_PATHNAME'
LANGUAGE C PARALLEL SAFE;
CREATE AGGREGATE pg_catalog.combine_agg(oid, bytea) (
STYPE = internal,
SFUNC = pg_catalog.combine_agg_sfunc,
FINALFUNC = pg_catalog.partial_agg_ffunc
);
CREATE AGGREGATE pg_catalog.finalize_agg(oid, bytea, anyelement) (
STYPE = internal,
SFUNC = pg_catalog.combine_agg_sfunc,
FINALFUNC = pg_catalog.combine_agg_ffunc,
FINALFUNC_EXTRA
);
REVOKE ALL ON FUNCTION pg_catalog.partial_agg_sfunc FROM PUBLIC;
REVOKE ALL ON FUNCTION pg_catalog.partial_agg_ffunc FROM PUBLIC;
REVOKE ALL ON FUNCTION pg_catalog.partial_agg FROM PUBLIC;
REVOKE ALL ON FUNCTION pg_catalog.combine_agg_sfunc(internal, oid, bytea, anyelement) FROM PUBLIC;
REVOKE ALL ON FUNCTION pg_catalog.combine_agg_sfunc(internal, oid, bytea) FROM PUBLIC;
REVOKE ALL ON FUNCTION pg_catalog.combine_agg_ffunc FROM PUBLIC;
REVOKE ALL ON FUNCTION pg_catalog.combine_agg FROM PUBLIC;
REVOKE ALL ON FUNCTION pg_catalog.finalize_agg FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pg_catalog.partial_agg_sfunc TO PUBLIC;
GRANT EXECUTE ON FUNCTION pg_catalog.partial_agg_ffunc TO PUBLIC;
GRANT EXECUTE ON FUNCTION pg_catalog.partial_agg TO PUBLIC;
GRANT EXECUTE ON FUNCTION pg_catalog.combine_agg_sfunc(internal, oid, bytea, anyelement) TO PUBLIC;
GRANT EXECUTE ON FUNCTION pg_catalog.combine_agg_sfunc(internal, oid, bytea) TO PUBLIC;
GRANT EXECUTE ON FUNCTION pg_catalog.combine_agg_ffunc TO PUBLIC;
GRANT EXECUTE ON FUNCTION pg_catalog.combine_agg TO PUBLIC;
GRANT EXECUTE ON FUNCTION pg_catalog.finalize_agg TO PUBLIC;
-- add pg_cimv TODO: finalize name of this table
CREATE TABLE citus.pg_cimv(
userview regclass NOT NULL PRIMARY KEY,
basetable regclass NOT NULL,
mattable regclass NOT NULL,
refreshview regclass NOT NULL,
deltatriggerfnnamespace name NOT NULL,
deltatriggerfnname name NOT NULL,
landingtable regclass NOT NULL,
jobid bigint NOT NULL
);
ALTER TABLE citus.pg_cimv SET SCHEMA pg_catalog;
GRANT SELECT ON pg_catalog.pg_cimv TO public;
RESET search_path; RESET search_path;

View File

@ -92,3 +92,14 @@ COMMENT ON FUNCTION master_drop_sequences(text[])
RESET search_path; RESET search_path;
DROP FUNCTION pg_catalog.undistribute_table(table_name regclass); DROP FUNCTION pg_catalog.undistribute_table(table_name regclass);
DROP AGGREGATE pg_catalog.finalize_agg(oid, bytea, anyelement);
DROP AGGREGATE pg_catalog.combine_agg(oid, bytea);
DROP FUNCTION pg_catalog.combine_agg_ffunc(internal, oid, bytea, anyelement);
DROP FUNCTION pg_catalog.combine_agg_sfunc(internal, oid, bytea);
DROP FUNCTION pg_catalog.combine_agg_sfunc(internal, oid, bytea, anyelement);
DROP AGGREGATE pg_catalog.partial_agg(oid, anyelement, int);
DROP FUNCTION pg_catalog.partial_agg_ffunc(internal);
DROP FUNCTION pg_catalog.partial_agg_sfunc(internal, oid, anyelement, int);
DROP TABLE pg_catalog.pg_cimv;

View File

@ -22,9 +22,11 @@
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "distributed/version_compat.h" #include "distributed/version_compat.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "parser/parse_agg.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/datum.h" #include "utils/datum.h"
#include "utils/expandeddatum.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/typcache.h" #include "utils/typcache.h"
@ -37,6 +39,11 @@ PG_FUNCTION_INFO_V1(worker_partial_agg_ffunc);
PG_FUNCTION_INFO_V1(coord_combine_agg_sfunc); PG_FUNCTION_INFO_V1(coord_combine_agg_sfunc);
PG_FUNCTION_INFO_V1(coord_combine_agg_ffunc); PG_FUNCTION_INFO_V1(coord_combine_agg_ffunc);
PG_FUNCTION_INFO_V1(partial_agg_sfunc);
PG_FUNCTION_INFO_V1(partial_agg_ffunc);
PG_FUNCTION_INFO_V1(combine_agg_sfunc);
PG_FUNCTION_INFO_V1(combine_agg_ffunc);
/* /*
* Holds information describing the structure of aggregation arguments * Holds information describing the structure of aggregation arguments
* and helps to efficiently handle both a single argument and multiple * and helps to efficiently handle both a single argument and multiple
@ -73,6 +80,11 @@ typedef struct StypeBox
AggregationArgumentContext *aggregationArgumentContext; AggregationArgumentContext *aggregationArgumentContext;
} StypeBox; } StypeBox;
/* TODO: replace PG_FUNCTION_ARGS with explicit parameters */
static Datum partial_agg_sfunc_internal(PG_FUNCTION_ARGS);
static Datum partial_agg_ffunc_internal(PG_FUNCTION_ARGS, bool serializeToCString);
static Datum combine_agg_sfunc_internal(PG_FUNCTION_ARGS, bool deserializeFromCString);
static Datum combine_agg_ffunc_internal(PG_FUNCTION_ARGS);
static HeapTuple GetAggregateForm(Oid oid, Form_pg_aggregate *form); static HeapTuple GetAggregateForm(Oid oid, Form_pg_aggregate *form);
static HeapTuple GetProcForm(Oid oid, Form_pg_proc *form); static HeapTuple GetProcForm(Oid oid, Form_pg_proc *form);
static HeapTuple GetTypeForm(Oid oid, Form_pg_type *form); static HeapTuple GetTypeForm(Oid oid, Form_pg_type *form);
@ -482,6 +494,62 @@ HandleStrictUninit(StypeBox *box, FunctionCallInfo fcinfo, Datum value)
} }
Datum
worker_partial_agg_sfunc(PG_FUNCTION_ARGS)
{
return partial_agg_sfunc_internal(fcinfo);
}
Datum
worker_partial_agg_ffunc(PG_FUNCTION_ARGS)
{
return partial_agg_ffunc_internal(fcinfo, true);
}
Datum
coord_combine_agg_sfunc(PG_FUNCTION_ARGS)
{
return combine_agg_sfunc_internal(fcinfo, true);
}
Datum
coord_combine_agg_ffunc(PG_FUNCTION_ARGS)
{
return combine_agg_ffunc_internal(fcinfo);
}
Datum
partial_agg_sfunc(PG_FUNCTION_ARGS)
{
return partial_agg_sfunc_internal(fcinfo);
}
Datum
partial_agg_ffunc(PG_FUNCTION_ARGS)
{
return partial_agg_ffunc_internal(fcinfo, false);
}
Datum
combine_agg_sfunc(PG_FUNCTION_ARGS)
{
return combine_agg_sfunc_internal(fcinfo, false);
}
Datum
combine_agg_ffunc(PG_FUNCTION_ARGS)
{
return combine_agg_ffunc_internal(fcinfo);
}
/* /*
* worker_partial_agg_sfunc advances transition state, * worker_partial_agg_sfunc advances transition state,
* essentially implementing the following pseudocode: * essentially implementing the following pseudocode:
@ -492,7 +560,7 @@ HandleStrictUninit(StypeBox *box, FunctionCallInfo fcinfo, Datum value)
* return box * return box
*/ */
Datum Datum
worker_partial_agg_sfunc(PG_FUNCTION_ARGS) partial_agg_sfunc_internal(PG_FUNCTION_ARGS)
{ {
StypeBox *box = NULL; StypeBox *box = NULL;
Form_pg_aggregate aggform; Form_pg_aggregate aggform;
@ -500,6 +568,7 @@ worker_partial_agg_sfunc(PG_FUNCTION_ARGS)
FmgrInfo info; FmgrInfo info;
int argumentIndex = 0; int argumentIndex = 0;
bool initialCall = PG_ARGISNULL(0); bool initialCall = PG_ARGISNULL(0);
int mode = PG_NARGS() < 4 ? 0 : PG_GETARG_INT32(3);
if (initialCall) if (initialCall)
{ {
@ -525,7 +594,25 @@ worker_partial_agg_sfunc(PG_FUNCTION_ARGS)
} }
HeapTuple aggtuple = GetAggregateForm(box->agg, &aggform); HeapTuple aggtuple = GetAggregateForm(box->agg, &aggform);
Oid aggsfunc = aggform->aggtransfn;
if (mode == 1 &&
(aggform->aggminvtransfn == 0 ||
aggform->aggtransfn != aggform->aggmtransfn))
{
ereport(ERROR, (errmsg("applying inverse state transition not supported "
"for this aggregate")));
}
Oid aggsfunc = InvalidOid;
if (mode == 1)
{
aggsfunc = aggform->aggminvtransfn;
}
else
{
aggsfunc = aggform->aggtransfn;
}
if (initialCall) if (initialCall)
{ {
@ -604,11 +691,11 @@ worker_partial_agg_sfunc(PG_FUNCTION_ARGS)
* worker_partial_agg_ffunc serializes transition state, * worker_partial_agg_ffunc serializes transition state,
* essentially implementing the following pseudocode: * essentially implementing the following pseudocode:
* *
* (box) -> text * (box) -> text/byte
* return box.agg.stype.output(box.value) * return box.agg.stype.output(box.value)
*/ */
Datum Datum
worker_partial_agg_ffunc(PG_FUNCTION_ARGS) partial_agg_ffunc_internal(PG_FUNCTION_ARGS, bool serializeToCString)
{ {
LOCAL_FCINFO(innerFcinfo, 1); LOCAL_FCINFO(innerFcinfo, 1);
FmgrInfo info; FmgrInfo info;
@ -635,27 +722,66 @@ worker_partial_agg_ffunc(PG_FUNCTION_ARGS)
"worker_partial_agg_ffunc expects an aggregate with COMBINEFUNC"))); "worker_partial_agg_ffunc expects an aggregate with COMBINEFUNC")));
} }
if (aggform->aggtranstype == INTERNALOID) if (serializeToCString && aggform->aggtranstype == INTERNALOID)
{ {
ereport(ERROR, ereport(ERROR,
(errmsg( (errmsg(
"worker_partial_agg_ffunc does not support aggregates with INTERNAL transition state"))); "worker_partial_agg_ffunc does not support aggregates with INTERNAL transition state")));
} }
Oid transtype = aggform->aggtranstype; Oid transtype = aggform->aggtranstype;
ReleaseSysCache(aggtuple); ReleaseSysCache(aggtuple);
getTypeOutputInfo(transtype, &typoutput, &typIsVarlena); Datum result = (Datum) 0;
bool isNull = false;
fmgr_info(typoutput, &info); /* TODO: move function call info into box to avoid initializing it repeatedly */
if (OidIsValid(aggform->aggserialfn))
{
Expr *serialfnexpr = NULL;
FmgrInfo serialfn;
build_aggregate_serialfn_expr(aggform->aggserialfn,
&serialfnexpr);
fmgr_info(aggform->aggserialfn, &serialfn);
fmgr_info_set_expr((Node *) serialfnexpr, &serialfn);
InitFunctionCallInfoData(*innerFcinfo, &info, 1, fcinfo->fncollation, LOCAL_FCINFO(serialfn_fcinfo, 2);
fcinfo->context, fcinfo->resultinfo); InitFunctionCallInfoData(*serialfn_fcinfo,
fcSetArgExt(innerFcinfo, 0, box->value, box->valueNull); &serialfn,
1,
InvalidOid,
(void *) fcinfo->context, NULL);
Datum result = FunctionCallInvoke(innerFcinfo); fcSetArgExt(serialfn_fcinfo, 0,
MakeExpandedObjectReadOnly(box->value, box->valueNull,
box->transtypeLen),
false);
if (innerFcinfo->isnull) result = FunctionCallInvoke(serialfn_fcinfo);
isNull = serialfn_fcinfo->isnull;
}
else
{
if (serializeToCString)
{
getTypeOutputInfo(transtype, &typoutput, &typIsVarlena);
}
else
{
getTypeBinaryOutputInfo(transtype, &typoutput, &typIsVarlena);
}
fmgr_info(typoutput, &info);
InitFunctionCallInfoData(*innerFcinfo, &info, 1, fcinfo->fncollation,
fcinfo->context, fcinfo->resultinfo);
fcSetArgExt(innerFcinfo, 0, box->value, box->valueNull);
result = FunctionCallInvoke(innerFcinfo);
isNull = innerFcinfo->isnull;
}
if (isNull)
{ {
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
@ -674,7 +800,7 @@ worker_partial_agg_ffunc(PG_FUNCTION_ARGS)
* return box * return box
*/ */
Datum Datum
coord_combine_agg_sfunc(PG_FUNCTION_ARGS) combine_agg_sfunc_internal(PG_FUNCTION_ARGS, bool deserializeFromCString)
{ {
LOCAL_FCINFO(innerFcinfo, 3); LOCAL_FCINFO(innerFcinfo, 3);
FmgrInfo info; FmgrInfo info;
@ -702,7 +828,7 @@ coord_combine_agg_sfunc(PG_FUNCTION_ARGS)
"coord_combine_agg_sfunc expects an aggregate with COMBINEFUNC"))); "coord_combine_agg_sfunc expects an aggregate with COMBINEFUNC")));
} }
if (aggform->aggtranstype == INTERNALOID) if (deserializeFromCString && aggform->aggtranstype == INTERNALOID)
{ {
ereport(ERROR, ereport(ERROR,
(errmsg( (errmsg(
@ -728,19 +854,67 @@ coord_combine_agg_sfunc(PG_FUNCTION_ARGS)
bool valueNull = PG_ARGISNULL(2); bool valueNull = PG_ARGISNULL(2);
HeapTuple transtypetuple = GetTypeForm(box->transtype, &transtypeform); HeapTuple transtypetuple = GetTypeForm(box->transtype, &transtypeform);
Oid ioparam = getTypeIOParam(transtypetuple); Oid ioparam = getTypeIOParam(transtypetuple);
Oid deserial = transtypeform->typinput; Oid deserial = deserializeFromCString ? transtypeform->typinput :
transtypeform->typreceive;
ReleaseSysCache(transtypetuple); ReleaseSysCache(transtypetuple);
fmgr_info(deserial, &info); bool strictDeserial = false;
if (valueNull && info.fn_strict) if (OidIsValid(aggform->aggdeserialfn))
{
strictDeserial = true;
}
else
{
fmgr_info(deserial, &info);
strictDeserial = info.fn_strict;
}
if (valueNull && strictDeserial)
{ {
value = (Datum) 0; value = (Datum) 0;
} }
/* TODO: store function call info in box to avoid recurring initialization overhead */
else if (OidIsValid(aggform->aggdeserialfn))
{
Expr *deserialfnexpr = NULL;
FmgrInfo deserialfn;
build_aggregate_deserialfn_expr(aggform->aggdeserialfn,
&deserialfnexpr);
fmgr_info(aggform->aggdeserialfn, &deserialfn);
fmgr_info_set_expr((Node *) deserialfnexpr, &deserialfn);
LOCAL_FCINFO(deserialfn_fcinfo, 2);
InitFunctionCallInfoData(*deserialfn_fcinfo,
&deserialfn,
2,
InvalidOid,
(void *) fcinfo->context, NULL);
fcSetArgExt(deserialfn_fcinfo, 0, PointerGetDatum(PG_GETARG_BYTEA_P(2)),
valueNull);
fcSetArgExt(deserialfn_fcinfo, 1, PointerGetDatum(NULL), false);
value = FunctionCallInvoke(deserialfn_fcinfo);
valueNull = deserialfn_fcinfo->isnull;
}
else else
{ {
InitFunctionCallInfoData(*innerFcinfo, &info, 3, fcinfo->fncollation, InitFunctionCallInfoData(*innerFcinfo, &info, 3, fcinfo->fncollation,
fcinfo->context, fcinfo->resultinfo); fcinfo->context, fcinfo->resultinfo);
fcSetArgExt(innerFcinfo, 0, PG_GETARG_DATUM(2), valueNull); if (deserializeFromCString)
{
fcSetArgExt(innerFcinfo, 0, PG_GETARG_DATUM(2), valueNull);
}
else
{
StringInfo string = makeStringInfo();
appendBinaryStringInfo(string,
VARDATA_ANY(PG_GETARG_DATUM(2)),
VARSIZE_ANY_EXHDR(PG_GETARG_DATUM(2)));
fcSetArgExt(innerFcinfo, 0, PointerGetDatum(string), valueNull);
}
fcSetArg(innerFcinfo, 1, ObjectIdGetDatum(ioparam)); fcSetArg(innerFcinfo, 1, ObjectIdGetDatum(ioparam));
fcSetArg(innerFcinfo, 2, Int32GetDatum(-1)); /* typmod */ fcSetArg(innerFcinfo, 2, Int32GetDatum(-1)); /* typmod */
@ -788,7 +962,7 @@ coord_combine_agg_sfunc(PG_FUNCTION_ARGS)
* return box.agg.ffunc(box.value) * return box.agg.ffunc(box.value)
*/ */
Datum Datum
coord_combine_agg_ffunc(PG_FUNCTION_ARGS) combine_agg_ffunc_internal(PG_FUNCTION_ARGS)
{ {
StypeBox *box = (StypeBox *) (PG_ARGISNULL(0) ? NULL : PG_GETARG_POINTER(0)); StypeBox *box = (StypeBox *) (PG_ARGISNULL(0) ? NULL : PG_GETARG_POINTER(0));
LOCAL_FCINFO(innerFcinfo, FUNC_MAX_ARGS); LOCAL_FCINFO(innerFcinfo, FUNC_MAX_ARGS);
@ -872,7 +1046,7 @@ TypecheckWorkerPartialAggArgType(FunctionCallInfo fcinfo, StypeBox *box)
return false; return false;
} }
Assert(list_length(aggref->args) == 2); Assert(list_length(aggref->args) == 2 || list_length(aggref->args) == 3);
TargetEntry *aggarg = list_nth(aggref->args, 1); TargetEntry *aggarg = list_nth(aggref->args, 1);
bool argtypesNull; bool argtypesNull;

View File

@ -0,0 +1,20 @@
#ifndef CIMV_H
#define CIMV_H
#include "postgres.h"
#include "nodes/plannodes.h"
#define CITUS_INTERNAL_SCHEMA "citus_internal"
#define CITUS_NAMESPACE "citus"
#define MATERIALIZATION_TABLE_SUFFIX "mt"
#define LANDING_TABLE_SUFFIX "ld"
#define REFRESH_VIEW_SUFFIX "rv"
extern bool ProcessCreateMaterializedViewStmt(const CreateTableAsStmt *stmt, const
char *query_string, PlannedStmt *pstmt);
extern void ProcessDropMaterializedViewStmt(DropStmt *stmt);
extern void ProcessDropViewStmt(DropStmt *stmt);
extern bool ProcessRefreshMaterializedViewStmt(RefreshMatViewStmt *stmt);
extern void RefreshCimv(Form_pg_cimv formCimv, bool skipData, bool isCreate);
#endif

View File

@ -203,6 +203,8 @@ extern Oid CitusCatalogNamespaceId(void);
extern Oid DistColocationRelationId(void); extern Oid DistColocationRelationId(void);
extern Oid DistColocationConfigurationIndexId(void); extern Oid DistColocationConfigurationIndexId(void);
extern Oid DistPartitionRelationId(void); extern Oid DistPartitionRelationId(void);
extern Oid PgCimvId(void);
extern Oid PgCimvIndexId(void);
extern Oid DistShardRelationId(void); extern Oid DistShardRelationId(void);
extern Oid DistPlacementRelationId(void); extern Oid DistPlacementRelationId(void);
extern Oid DistNodeRelationId(void); extern Oid DistNodeRelationId(void);

View File

@ -23,6 +23,7 @@
#include "catalog/objectaddress.h" #include "catalog/objectaddress.h"
#include "distributed/citus_nodes.h" #include "distributed/citus_nodes.h"
#include "distributed/relay_utility.h" #include "distributed/relay_utility.h"
#include "distributed/pg_cimv.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/relcache.h" #include "utils/relcache.h"
@ -125,6 +126,9 @@ extern uint64 InsertShardPlacementRow(uint64 shardId, uint64 placementId,
extern void InsertIntoPgDistPartition(Oid relationId, char distributionMethod, extern void InsertIntoPgDistPartition(Oid relationId, char distributionMethod,
Var *distributionColumn, uint32 colocationId, Var *distributionColumn, uint32 colocationId,
char replicationModel); char replicationModel);
extern void InsertIntoPgCimv(Form_pg_cimv cimv);
extern void DeletePgCimvRow(Oid userViewId);
extern Form_pg_cimv LookupCimvFromCatalog(Oid userViewId, bool missingOk);
extern void DeletePartitionRow(Oid distributedRelationId); extern void DeletePartitionRow(Oid distributedRelationId);
extern void DeleteShardRow(uint64 shardId); extern void DeleteShardRow(uint64 shardId);
extern void UpdatePartitionShardPlacementStates(ShardPlacement *parentShardPlacement, extern void UpdatePartitionShardPlacementStates(ShardPlacement *parentShardPlacement,

View File

@ -0,0 +1,51 @@
/*-------------------------------------------------------------------------
*
* pg_cimv.h
* TODO
*
* Copyright (c) Citus Data, Inc.
*
*-------------------------------------------------------------------------
*/
#ifndef PG_CIMV_H
#define PG_CIMV_H
/* ----------------
* pg_cimv definition.
* ----------------
*/
typedef struct FormData_pg_cimv
{
Oid userview;
Oid basetable;
Oid mattable;
Oid refreshview;
NameData triggerfnnamespace;
NameData triggerfnname;
Oid landingtable;
int64 jobid;
} FormData_pg_cimv;
/* ----------------
* FormData_pg_cimv corresponds to a pointer to a tuple with
* the format of pg_cimv relation.
* ----------------
*/
typedef FormData_pg_cimv *Form_pg_cimv;
/* ----------------
* compiler constants for pg_cimv
* ----------------
*/
#define Natts_pg_cimv 8
#define Anum_pg_cimv_userview 1
#define Anum_pg_cimv_basetable 2
#define Anum_pg_cimv_mattable 3
#define Anum_pg_cimv_refreshview 4
#define Anum_pg_cimv_triggernamespace 5
#define Anum_pg_cimv_triggername 6
#define Anum_pg_cimv_landingtable 7
#define Anum_pg_cimv_jobid 8
#endif /* PG_CIMV_H */

File diff suppressed because it is too large Load Diff

View File

@ -448,10 +448,19 @@ SELECT * FROM print_extension_changes();
function task_tracker_task_status(bigint,integer) | function task_tracker_task_status(bigint,integer) |
function worker_execute_sql_task(bigint,integer,text,boolean) | function worker_execute_sql_task(bigint,integer,text,boolean) |
function worker_merge_files_and_run_query(bigint,integer,text,text) | function worker_merge_files_and_run_query(bigint,integer,text,text) |
| function combine_agg(oid,bytea)
| function combine_agg_ffunc(internal,oid,bytea,anyelement)
| function combine_agg_sfunc(internal,oid,bytea)
| function combine_agg_sfunc(internal,oid,bytea,anyelement)
| function create_citus_local_table(regclass) | function create_citus_local_table(regclass)
| function finalize_agg(oid,bytea,anyelement)
| function partial_agg(oid,anyelement,integer)
| function partial_agg_ffunc(internal)
| function partial_agg_sfunc(internal,oid,anyelement,integer)
| function undistribute_table(regclass) | function undistribute_table(regclass)
| function worker_record_sequence_dependency(regclass,regclass,name) | function worker_record_sequence_dependency(regclass,regclass,name)
(10 rows) | table pg_cimv
(19 rows)
DROP TABLE prev_objects, extension_diff; DROP TABLE prev_objects, extension_diff;
-- show running version -- show running version

View File

@ -96,7 +96,7 @@ test: multi_subquery_in_where_reference_clause join geqo adaptive_executor propa
test: multi_subquery_union multi_subquery_in_where_clause multi_subquery_misc statement_cancel_error_message test: multi_subquery_union multi_subquery_in_where_clause multi_subquery_misc statement_cancel_error_message
test: multi_agg_distinct multi_agg_approximate_distinct multi_limit_clause_approximate multi_outer_join_reference multi_single_relation_subquery multi_prepare_plsql set_role_in_transaction test: multi_agg_distinct multi_agg_approximate_distinct multi_limit_clause_approximate multi_outer_join_reference multi_single_relation_subquery multi_prepare_plsql set_role_in_transaction
test: multi_reference_table multi_select_for_update relation_access_tracking pg13_with_ties test: multi_reference_table multi_select_for_update relation_access_tracking pg13_with_ties
test: custom_aggregate_support aggregate_support tdigest_aggregate_support test: custom_aggregate_support aggregate_support tdigest_aggregate_support cimv
test: multi_average_expression multi_working_columns multi_having_pushdown having_subquery test: multi_average_expression multi_working_columns multi_having_pushdown having_subquery
test: multi_array_agg multi_limit_clause multi_orderby_limit_pushdown test: multi_array_agg multi_limit_clause multi_orderby_limit_pushdown
test: multi_jsonb_agg multi_jsonb_object_agg multi_json_agg multi_json_object_agg bool_agg ch_bench_having chbenchmark_all_queries expression_reference_join anonymous_columns test: multi_jsonb_agg multi_jsonb_object_agg multi_json_agg multi_json_object_agg bool_agg ch_bench_having chbenchmark_all_queries expression_reference_join anonymous_columns

View File

@ -0,0 +1,360 @@
--
-- CIMV
-- Tests for Citus Incremental Materialized Views
--
\set VERBOSITY terse
SET citus.next_shard_id TO 400000;
CREATE SCHEMA cimv;
SET search_path TO cimv, public;
SET citus.shard_count TO 4;
CREATE TABLE events (a int, b int, c double precision, d timestamp, e bigint);
INSERT INTO events
SELECT v % 10 AS a,
v % 100 AS b,
v / 3.0 AS c,
timestamp '2020-01-01 20:00:00' +
((v / 10000.0) * (timestamp '2020-01-01 15:00:00' -
timestamp '2020-01-01 10:00:00')) AS d,
v AS e
FROM generate_series(1, 10000) v;
CREATE MATERIALIZED VIEW mv WITH (citus.cimv) AS
SELECT a,
date_trunc('hour', d) AS d_hour,
min(b) AS min_b,
max(b) AS max_b,
avg(b) AS avg_b,
min(c) AS min_c,
max(c) AS max_c,
avg(c) AS avg_c,
min(e) AS min_e,
max(e) AS max_e,
avg(e) AS avg_e
FROM events
WHERE b > 10
GROUP BY a, d_hour;
SELECT a,
d_hour,
min_b::numeric(12,2),
max_b::numeric(12,2),
avg_b::numeric(12,2),
min_c::numeric(12,2),
max_c::numeric(12,2),
avg_c::numeric(12,2),
min_e::numeric(12,2),
max_e::numeric(12,2),
avg_e::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
INSERT INTO events
SELECT v % 10 AS a,
v % 100 AS b,
v / 3.0 AS c,
timestamp '2020-01-01 20:00:00' +
((v / 10000.0) * (timestamp '2020-01-01 15:00:00' -
timestamp '2020-01-01 10:00:00')) AS d,
v AS e
FROM generate_series(10000, 11000) v;
SELECT a,
d_hour,
min_b::numeric(12,2),
max_b::numeric(12,2),
avg_b::numeric(12,2),
min_c::numeric(12,2),
max_c::numeric(12,2),
avg_c::numeric(12,2),
min_e::numeric(12,2),
max_e::numeric(12,2),
avg_e::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DELETE FROM events WHERE b < 100;
DROP VIEW mv;
DROP MATERIALIZED VIEW mv;
CREATE MATERIALIZED VIEW mv WITH (citus.cimv) AS
SELECT a,
date_trunc('hour', d) AS d_hour,
avg(b) AS avg_b
FROM events
WHERE b > 10
GROUP BY a, d_hour;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DELETE FROM events WHERE b < 20;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
UPDATE events SET b = b + b;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DROP MATERIALIZED VIEW mv;
CREATE MATERIALIZED VIEW mv WITH (citus.cimv, citus.insertonlycapture) AS
SELECT a,
date_trunc('hour', d) AS d_hour,
avg(b) AS avg_b
FROM events
WHERE b > 10
GROUP BY a, d_hour;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
INSERT INTO events
SELECT v % 10 AS a,
v % 100 AS b,
v / 3.0 AS c,
timestamp '2020-01-01 20:00:00' +
((v / 10000.0) * (timestamp '2020-01-01 15:00:00' -
timestamp '2020-01-01 10:00:00')) AS d,
v AS e
FROM generate_series(11000, 12000) v;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DELETE FROM events WHERE b < 100;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
UPDATE events SET b = b + b;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
REFRESH MATERIALIZED VIEW mv WITH NO DATA;
SELECT * FROM mv;
REFRESH MATERIALIZED VIEW mv;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DROP MATERIALIZED VIEW mv;
CREATE MATERIALIZED VIEW mv WITH (citus.cimv, citus.insertonlycapture) AS
SELECT a,
date_trunc('hour', d) AS d_hour,
avg(b) AS avg_b
FROM events
WHERE b > 10
GROUP BY a, d_hour WITH NO DATA;
SELECT * FROM mv;
DROP MATERIALIZED VIEW mv;
SELECT create_distributed_table('events', 'a');
CREATE MATERIALIZED VIEW mv WITH (citus.cimv) AS
SELECT a,
date_trunc('hour', d) AS d_hour,
min(b) AS min_b,
max(b) AS max_b,
avg(b) AS avg_b,
min(c) AS min_c,
max(c) AS max_c,
avg(c) AS avg_c,
min(e) AS min_e,
max(e) AS max_e,
avg(e) AS avg_e
FROM events
WHERE b > 10
GROUP BY a, d_hour;
SELECT a,
d_hour,
min_b::numeric(12,2),
max_b::numeric(12,2),
avg_b::numeric(12,2),
min_c::numeric(12,2),
max_c::numeric(12,2),
avg_c::numeric(12,2),
min_e::numeric(12,2),
max_e::numeric(12,2),
avg_e::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
INSERT INTO events
SELECT v % 10 AS a,
v % 100 AS b,
v / 3.0 AS c,
timestamp '2020-01-01 20:00:00' +
((v / 10000.0) * (timestamp '2020-01-01 15:00:00' -
timestamp '2020-01-01 10:00:00')) AS d,
v AS e
FROM generate_series(12000, 13000) v;
SELECT a,
d_hour,
min_b::numeric(12,2),
max_b::numeric(12,2),
avg_b::numeric(12,2),
min_c::numeric(12,2),
max_c::numeric(12,2),
avg_c::numeric(12,2),
min_e::numeric(12,2),
max_e::numeric(12,2),
avg_e::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DELETE FROM events WHERE b < 100;
DROP VIEW mv;
DROP MATERIALIZED VIEW mv;
CREATE MATERIALIZED VIEW mv WITH (citus.cimv) AS
SELECT a,
date_trunc('hour', d) AS d_hour,
avg(b) AS avg_b
FROM events
WHERE b > 10
GROUP BY a, d_hour;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DELETE FROM events WHERE b < 20;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
UPDATE events SET b = b + b;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DROP MATERIALIZED VIEW mv;
CREATE MATERIALIZED VIEW mv WITH (citus.cimv, citus.insertonlycapture) AS
SELECT a,
date_trunc('hour', d) AS d_hour,
avg(b) AS avg_b
FROM events
WHERE b > 10
GROUP BY a, d_hour;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
INSERT INTO events
SELECT v % 10 AS a,
v % 100 AS b,
v / 3.0 AS c,
timestamp '2020-01-01 20:00:00' +
((v / 10000.0) * (timestamp '2020-01-01 15:00:00' -
timestamp '2020-01-01 10:00:00')) AS d,
v AS e
FROM generate_series(13000, 14000) v;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DELETE FROM events WHERE b < 100;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
UPDATE events SET b = b + b;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
REFRESH MATERIALIZED VIEW mv WITH NO DATA;
SELECT * FROM mv;
REFRESH MATERIALIZED VIEW mv;
SELECT a,
d_hour,
avg_b::numeric(12,2)
FROM mv
ORDER BY a, d_hour;
DROP MATERIALIZED VIEW mv;
CREATE MATERIALIZED VIEW mv WITH (citus.cimv, citus.insertonlycapture) AS
SELECT a,
date_trunc('hour', d) AS d_hour,
avg(b) AS avg_b
FROM events
WHERE b > 10
GROUP BY a, d_hour WITH NO DATA;
SELECT * FROM mv;
DROP MATERIALIZED VIEW mv;
SET client_min_messages TO WARNING; -- suppress cascade messages
DROP SCHEMA cimv CASCADE;