diff --git a/doc/src/sgml/ref/create_warehouse.sgml b/doc/src/sgml/ref/create_warehouse.sgml new file mode 100644 index 00000000000..65ba0cf272f --- /dev/null +++ b/doc/src/sgml/ref/create_warehouse.sgml @@ -0,0 +1,53 @@ + + + + + CREATE WAREHOUSE + + + + CREATE WAREHOUSE + 7 + SQL - Language Statements + + + + CREATE WAREHOUSE + define a new warehouse for query processing + + + + +CREATE WAREHOUSE name +[ WAREHOUSE_SIZE size ] + + + + + Description + + + CREATE WAREHOUSE Creates a new virtual warehouse in the system. + Initial creation of a virtual warehouse might take some time to provision the compute resources. + + + + + + Parameters + + + WAREHOUSE_SIZE + + + The size of the warehouse. + + + + + + + diff --git a/gpcontrib/gp_inject_fault/gp_inject_fault.c b/gpcontrib/gp_inject_fault/gp_inject_fault.c index 22c31cf72a0..009873941d7 100644 --- a/gpcontrib/gp_inject_fault/gp_inject_fault.c +++ b/gpcontrib/gp_inject_fault/gp_inject_fault.c @@ -119,35 +119,46 @@ get_segment_configuration(int dbid, char **hostname, int *port, int *content) SysScanDesc scan; Datum attr; bool isNull; + Oid warehouseid = InvalidOid; + bool find_config = false; configrel = table_open(GpSegmentConfigRelationId, AccessShareLock); ScanKeyInit(&scankey[0], Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); - scan = systable_beginscan(configrel, GpSegmentConfigDbidIndexId, true, + scan = systable_beginscan(configrel, GpSegmentConfigDbidWarehouseIndexId, true, NULL, 1, scankey); - tuple = systable_getnext(scan); - - if (HeapTupleIsValid(tuple)) + while (HeapTupleIsValid(tuple = systable_getnext(scan))) { - attr = heap_getattr(tuple, Anum_gp_segment_configuration_hostname, + attr = heap_getattr(tuple, Anum_gp_segment_configuration_warehouseid, RelationGetDescr(configrel), &isNull); Assert(!isNull); - *hostname = TextDatumGetCString(attr); + warehouseid = DatumGetObjectId(attr); - attr = heap_getattr(tuple, Anum_gp_segment_configuration_port, - RelationGetDescr(configrel), &isNull); - Assert(!isNull); - *port = DatumGetInt32(attr); + if (!OidIsValid(warehouseid) || warehouseid == GetCurrentWarehouseId()) + { + attr = heap_getattr(tuple, Anum_gp_segment_configuration_hostname, + RelationGetDescr(configrel), &isNull); + Assert(!isNull); + *hostname = TextDatumGetCString(attr); - attr = heap_getattr(tuple, Anum_gp_segment_configuration_content, - RelationGetDescr(configrel), &isNull); - Assert(!isNull); - *content = DatumGetInt32(attr); + attr = heap_getattr(tuple, Anum_gp_segment_configuration_port, + RelationGetDescr(configrel), &isNull); + Assert(!isNull); + *port = DatumGetInt32(attr); + + attr = heap_getattr(tuple, Anum_gp_segment_configuration_content, + RelationGetDescr(configrel), &isNull); + Assert(!isNull); + *content = DatumGetInt32(attr); + + find_config = true; + break; + } } - else + if (!find_config) elog(ERROR, "dbid %d not found", dbid); systable_endscan(scan); diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 0fe440e8d98..6b800053526 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -78,6 +78,7 @@ CATALOG_HEADERS := \ pg_resqueue.h pg_resqueuecapability.h pg_resourcetype.h \ pg_resgroup.h pg_resgroupcapability.h \ gp_configuration_history.h gp_id.h gp_distribution_policy.h gp_version_at_initdb.h \ + gp_warehouse.h \ pg_appendonly.h \ gp_fastsequence.h pg_extprotocol.h \ pg_attribute_encoding.h \ diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 52112416628..814188d1ade 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -59,6 +59,7 @@ #include "catalog/gp_configuration_history.h" #include "catalog/gp_id.h" #include "catalog/gp_version_at_initdb.h" +#include "catalog/gp_warehouse.h" #include "catalog/pg_event_trigger.h" #include "catalog/pg_largeobject_metadata.h" #include "catalog/pg_resourcetype.h" @@ -459,8 +460,8 @@ IsSharedRelation(Oid relationId) relationId == AuthIdRolResQueueIndexId || relationId == AuthIdRolResGroupIndexId || #ifdef USE_INTERNAL_FTS - relationId == GpSegmentConfigContentPreferred_roleIndexId || - relationId == GpSegmentConfigDbidIndexId || + relationId == GpSegmentConfigContentPreferred_roleWarehouseIndexId || + relationId == GpSegmentConfigDbidWarehouseIndexId || #endif relationId == AuthTimeConstraintAuthIdIndexId) { @@ -505,6 +506,14 @@ IsSharedRelation(Oid relationId) return true; } + /* warehouse table and its indexes */ + if (relationId == GpWarehouseRelationId || + relationId == GpWarehouseOidIndexId || + relationId == GpWarehouseNameIndexId) + { + return true; + } + return false; } diff --git a/src/backend/cdb/cdbutil.c b/src/backend/cdb/cdbutil.c index 09d77d2cde4..0d6f7147d30 100644 --- a/src/backend/cdb/cdbutil.c +++ b/src/backend/cdb/cdbutil.c @@ -241,6 +241,7 @@ readGpSegConfigFromCatalog(int *total_dbs) int array_size; bool isNull; Datum attr; + Oid warehouseid = InvalidOid; Relation gp_seg_config_rel; HeapTuple gp_seg_config_tuple = NULL; SysScanDesc gp_seg_config_scan; @@ -256,6 +257,13 @@ readGpSegConfigFromCatalog(int *total_dbs) while (HeapTupleIsValid(gp_seg_config_tuple = systable_getnext(gp_seg_config_scan))) { + /* warehouseid */ + attr = heap_getattr(gp_seg_config_tuple, Anum_gp_segment_configuration_warehouseid, RelationGetDescr(gp_seg_config_rel), &isNull); + Assert(!isNull); + warehouseid = DatumGetObjectId(attr); + if (OidIsValid(warehouseid) && warehouseid != GetCurrentWarehouseId()) + continue; + config = &configs[idx]; /* dbid */ @@ -1511,93 +1519,101 @@ dbid_get_dbinfo(int16 dbid) Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); - scan = systable_beginscan(rel, GpSegmentConfigDbidIndexId, true, + scan = systable_beginscan(rel, GpSegmentConfigDbidWarehouseIndexId, true, NULL, 1, &scankey); - tuple = systable_getnext(scan); - if (HeapTupleIsValid(tuple)) + while (HeapTupleIsValid(tuple = systable_getnext(scan))) { Datum attr; bool isNull; + Oid warehouseid = InvalidOid; - i = palloc(sizeof(GpSegConfigEntry)); - - /* - * dbid - */ - attr = heap_getattr(tuple, Anum_gp_segment_configuration_dbid, + attr = heap_getattr(tuple, Anum_gp_segment_configuration_warehouseid, RelationGetDescr(rel), &isNull); Assert(!isNull); - i->dbid = DatumGetInt16(attr); + warehouseid = DatumGetObjectId(attr); - /* - * content - */ - attr = heap_getattr(tuple, Anum_gp_segment_configuration_content, - RelationGetDescr(rel), &isNull); - Assert(!isNull); - i->segindex = DatumGetInt16(attr); + if (!OidIsValid(warehouseid) || warehouseid == GetCurrentWarehouseId()) + { + i = palloc(sizeof(GpSegConfigEntry)); - /* - * role - */ - attr = heap_getattr(tuple, Anum_gp_segment_configuration_role, - RelationGetDescr(rel), &isNull); - Assert(!isNull); - i->role = DatumGetChar(attr); + /* + * dbid + */ + attr = heap_getattr(tuple, Anum_gp_segment_configuration_dbid, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->dbid = DatumGetInt16(attr); - /* - * preferred-role - */ - attr = heap_getattr(tuple, - Anum_gp_segment_configuration_preferred_role, - RelationGetDescr(rel), &isNull); - Assert(!isNull); - i->preferred_role = DatumGetChar(attr); + /* + * content + */ + attr = heap_getattr(tuple, Anum_gp_segment_configuration_content, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->segindex = DatumGetInt16(attr); - /* - * mode - */ - attr = heap_getattr(tuple, Anum_gp_segment_configuration_mode, - RelationGetDescr(rel), &isNull); - Assert(!isNull); - i->mode = DatumGetChar(attr); + /* + * role + */ + attr = heap_getattr(tuple, Anum_gp_segment_configuration_role, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->role = DatumGetChar(attr); - /* - * status - */ - attr = heap_getattr(tuple, Anum_gp_segment_configuration_status, - RelationGetDescr(rel), &isNull); - Assert(!isNull); - i->status = DatumGetChar(attr); + /* + * preferred-role + */ + attr = heap_getattr(tuple, + Anum_gp_segment_configuration_preferred_role, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->preferred_role = DatumGetChar(attr); - /* - * hostname - */ - attr = heap_getattr(tuple, Anum_gp_segment_configuration_hostname, - RelationGetDescr(rel), &isNull); - Assert(!isNull); - i->hostname = TextDatumGetCString(attr); + /* + * mode + */ + attr = heap_getattr(tuple, Anum_gp_segment_configuration_mode, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->mode = DatumGetChar(attr); - /* - * address - */ - attr = heap_getattr(tuple, Anum_gp_segment_configuration_address, - RelationGetDescr(rel), &isNull); - Assert(!isNull); - i->address = TextDatumGetCString(attr); + /* + * status + */ + attr = heap_getattr(tuple, Anum_gp_segment_configuration_status, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->status = DatumGetChar(attr); - /* - * port - */ - attr = heap_getattr(tuple, Anum_gp_segment_configuration_port, - RelationGetDescr(rel), &isNull); - Assert(!isNull); - i->port = DatumGetInt32(attr); + /* + * hostname + */ + attr = heap_getattr(tuple, Anum_gp_segment_configuration_hostname, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->hostname = TextDatumGetCString(attr); - Assert(systable_getnext(scan) == NULL); /* should be only 1 */ + /* + * address + */ + attr = heap_getattr(tuple, Anum_gp_segment_configuration_address, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->address = TextDatumGetCString(attr); + + /* + * port + */ + attr = heap_getattr(tuple, Anum_gp_segment_configuration_port, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + i->port = DatumGetInt32(attr); + + break; + } } - else + if (i == NULL) { elog(ERROR, "could not find configuration entry for dbid %i", dbid); } @@ -1619,7 +1635,8 @@ contentid_get_dbid(int16 contentid, char role, bool getPreferredRoleNotCurrentRo { int16 dbid = 0; Relation rel; - ScanKeyData scankey[2]; + ScanKeyData scankey[3]; + int nkeys = 2; SysScanDesc scan; HeapTuple tup; @@ -1648,8 +1665,17 @@ contentid_get_dbid(int16 contentid, char role, bool getPreferredRoleNotCurrentRo Anum_gp_segment_configuration_preferred_role, BTEqualStrategyNumber, F_CHAREQ, CharGetDatum(role)); - scan = systable_beginscan(rel, GpSegmentConfigContentPreferred_roleIndexId, true, - NULL, 2, scankey); + if (contentid != MASTER_CONTENT_ID) + { + nkeys++; + ScanKeyInit(&scankey[2], + Anum_gp_segment_configuration_warehouseid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(GetCurrentWarehouseId())); + } + + scan = systable_beginscan(rel, GpSegmentConfigContentPreferred_roleWarehouseIndexId, true, + NULL, nkeys, scankey); } else { @@ -1665,9 +1691,17 @@ contentid_get_dbid(int16 contentid, char role, bool getPreferredRoleNotCurrentRo Anum_gp_segment_configuration_role, BTEqualStrategyNumber, F_CHAREQ, CharGetDatum(role)); + if (contentid != MASTER_CONTENT_ID) + { + nkeys++; + ScanKeyInit(&scankey[2], + Anum_gp_segment_configuration_warehouseid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(GetCurrentWarehouseId())); + } /* no index */ scan = systable_beginscan(rel, InvalidOid, false, - NULL, 2, scankey); + NULL, nkeys, scankey); } tup = systable_getnext(scan); diff --git a/src/backend/fts/fts.c b/src/backend/fts/fts.c index cdec9dcf7aa..3da780092d4 100644 --- a/src/backend/fts/fts.c +++ b/src/backend/fts/fts.c @@ -228,18 +228,22 @@ probeWalRepUpdateConfig(int16 dbid, int16 segindex, char role, bool confignulls[Natts_gp_segment_configuration] = { false }; bool repls[Natts_gp_segment_configuration] = { false }; - ScanKeyData scankey; + ScanKeyData scankey[2]; SysScanDesc sscan; configrel = table_open(GpSegmentConfigRelationId, RowExclusiveLock); - ScanKeyInit(&scankey, + ScanKeyInit(&scankey[0], Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); - sscan = systable_beginscan(configrel, GpSegmentConfigDbidIndexId, - true, NULL, 1, &scankey); + ScanKeyInit(&scankey[1], + Anum_gp_segment_configuration_warehouseid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(GetCurrentWarehouseId())); + sscan = systable_beginscan(configrel, GpSegmentConfigDbidWarehouseIndexId, + true, NULL, 2, scankey); configtuple = systable_getnext(sscan); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 4f286ad13a4..45e22f74bab 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -294,8 +294,8 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt CreateAssertionStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt - CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt - DropOpClassStmt DropOpFamilyStmt DropStmt + CreatedbStmt CreateWarehouseStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt + DropOpClassStmt DropOpFamilyStmt DropStmt DropWarehouseStmt DropCastStmt DropRoleStmt DropdbStmt DropTableSpaceStmt DropTransformStmt @@ -705,6 +705,8 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ %type hash_partbound %type hash_partbound_elem +%type OptWarehouseOptList WarehouseOptList +%type WarehouseOptElem /* * Non-keyword token types. These are hard-wired into the "flex" lexer. @@ -872,6 +874,10 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ VALIDATION + WAREHOUSE + + WAREHOUSE_SIZE + WEB WRITABLE /* @@ -1420,6 +1426,7 @@ stmt: | CreateOpClassStmt | CreateOpFamilyStmt | CreatePublicationStmt + | CreateWarehouseStmt | AlterOpFamilyStmt | CreatePolicyStmt | CreatePLangStmt @@ -1459,6 +1466,7 @@ stmt: | DropRoleStmt | DropUserMappingStmt | DropdbStmt + | DropWarehouseStmt | ExecuteStmt | ExplainStmt | FetchStmt @@ -12333,6 +12341,48 @@ publication_for_tables: ; +/***************************************************************************** + * + * QUERY: + * CREATE WAREHOUSE name + * [WAREHOUSE_SIZE ] + * + *****************************************************************************/ + +CreateWarehouseStmt: CREATE WAREHOUSE name OptWarehouseOptList + { + CreateWarehouseStmt *n = makeNode(CreateWarehouseStmt); + n->whname = $3; + n->options = $4; + $$ = (Node *) n; + } + ; + +OptWarehouseOptList: WarehouseOptList { $$ = $1; } + | /*EMPTY*/ { $$ = NIL; } + ; + +WarehouseOptList: WarehouseOptElem { $$ = list_make1($1); } + | WarehouseOptList WarehouseOptElem { $$ = lappend($1, $2); } + ; + +WarehouseOptElem: + WAREHOUSE_SIZE SignedIconst + { + $$ = makeDefElem("warehouse_size", (Node *)makeInteger($2), @1); + } + ; + + +DropWarehouseStmt: DROP WAREHOUSE name + { + DropWarehouseStmt *n = makeNode(DropWarehouseStmt); + n->whname = $3; + $$ = (Node *) n; + } + ; + + /***************************************************************************** * * ALTER PUBLICATION name SET ( options ) @@ -18795,6 +18845,8 @@ unreserved_keyword: | VIEW | VIEWS | VOLATILE + | WAREHOUSE + | WAREHOUSE_SIZE | WEB /* gp */ | WHITESPACE_P | WITHIN @@ -19783,6 +19835,8 @@ bare_label_keyword: | VIEW | VIEWS | VOLATILE + | WAREHOUSE + | WAREHOUSE_SIZE | WEB | WHEN | WHITESPACE_P diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index e4bc2f0c977..34c17a00db0 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -803,6 +803,26 @@ GxactLockTableWait(DistributedTransactionId gxid) LockRelease(&tag, ShareLock, false); } +void +LockWarehouse(Oid warehouseOid, LOCKMODE lockmode) +{ + LOCKTAG tag; + + SET_LOCKTAG_WAREHOUSE(tag, warehouseOid); + + (void) LockAcquire(&tag, lockmode, true, false); +} + +void +UnlockWarehouse(Oid warehouseOid, LOCKMODE lockmode) +{ + LOCKTAG tag; + + SET_LOCKTAG_WAREHOUSE(tag, warehouseOid); + + LockRelease(&tag, lockmode, true); +} + /* * ConditionalXactLockTableWait * @@ -1284,6 +1304,11 @@ DescribeLockTag(StringInfo buf, const LOCKTAG *tag) _("resource queue %u"), tag->locktag_field1); break; + case LOCKTAG_WAREHOUSE: + appendStringInfo(buf, + _("warehouse %u"), + tag->locktag_field1); + break; default: appendStringInfo(buf, _("unrecognized locktag type %d"), @@ -1330,6 +1355,7 @@ LockTagIsTemp(const LOCKTAG *tag) break; case LOCKTAG_USERLOCK: case LOCKTAG_ADVISORY: + case LOCKTAG_WAREHOUSE: /* assume these aren't temp */ break; } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 966b355e98e..b558ae1db4d 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -241,8 +241,10 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_DropTaskStmt: case T_DropQueueStmt: case T_DropResourceGroupStmt: + case T_DropWarehouseStmt: case T_CreateExternalStmt: case T_RetrieveStmt: + case T_CreateWarehouseStmt: { /* DDL is not read-only, and neither is TRUNCATE. */ return COMMAND_IS_NOT_READ_ONLY; @@ -3729,6 +3731,13 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_RETRIEVE; break; + case T_CreateWarehouseStmt: + tag = CMDTAG_CREATE_WAREHOUSE; + break; + case T_DropWarehouseStmt: + tag = CMDTAG_DROP_WAREHOUSE; + break; + default: elog(WARNING, "unrecognized node type: %d", (int) nodeTag(parsetree)); @@ -4206,6 +4215,14 @@ GetCommandLogLevel(Node *parsetree) case T_AlterCollationStmt: lev = LOGSTMT_DDL; break; + + case T_CreateWarehouseStmt: + lev = LOGSTMT_DDL; + break; + + case T_DropWarehouseStmt: + lev = LOGSTMT_DDL; + break; /* already-planned queries */ case T_PlannedStmt: diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 7afbbd33817..bc0da11a729 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -44,10 +44,11 @@ const char *const LockTagTypeNames[] = { "resource queue", "distributed xid", "userlock", - "advisory" + "advisory", + "warehouse" }; -StaticAssertDecl(lengthof(LockTagTypeNames) == (LOCKTAG_ADVISORY + 1), +StaticAssertDecl(lengthof(LockTagTypeNames) == (LOCKTAG_WAREHOUSE + 1), "array length mismatch"); /* This must match enum PredicateLockTargetType (predicate_internals.h) */ @@ -459,6 +460,7 @@ pg_lock_status(PG_FUNCTION_ARGS) nulls[9] = true; break; case LOCKTAG_RESOURCE_QUEUE: + case LOCKTAG_WAREHOUSE: #if 0 values[1] = ObjectIdGetDatum(proc->databaseId); #endif diff --git a/src/backend/utils/gp/segadmin.c b/src/backend/utils/gp/segadmin.c index 31baed7394e..cc2eacb31fb 100644 --- a/src/backend/utils/gp/segadmin.c +++ b/src/backend/utils/gp/segadmin.c @@ -194,13 +194,24 @@ remove_segment_config(int16 dbid) Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); - - sscan = systable_beginscan(rel, GpSegmentConfigDbidIndexId, true, + sscan = systable_beginscan(rel, GpSegmentConfigDbidWarehouseIndexId, true, NULL, 1, &scankey); while ((tuple = systable_getnext(sscan)) != NULL) { - CatalogTupleDelete(rel, &tuple->t_self); - numDel++; + Datum attr; + bool isNull; + Oid warehouseid = InvalidOid; + + attr = heap_getattr(tuple, Anum_gp_segment_configuration_warehouseid, + RelationGetDescr(rel), &isNull); + Assert(!isNull); + warehouseid = DatumGetObjectId(attr); + + if (!OidIsValid(warehouseid) || warehouseid == GetCurrentWarehouseId()) + { + CatalogTupleDelete(rel, &tuple->t_self); + numDel++; + } } systable_endscan(sscan); @@ -240,6 +251,8 @@ add_segment_config_entry(GpSegConfigEntry *i) CStringGetTextDatum(i->address); values[Anum_gp_segment_configuration_datadir - 1] = CStringGetTextDatum(i->datadir); + values[Anum_gp_segment_configuration_warehouseid - 1] = + ObjectIdGetDatum(i->warehouseid); tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); @@ -393,6 +406,11 @@ gp_add_segment(PG_FUNCTION_ARGS) elog(ERROR, "datadir cannot be NULL"); new.datadir = TextDatumGetCString(PG_GETARG_DATUM(9)); + if (new.segindex == MASTER_CONTENT_ID) + new.warehouseid = InvalidOid; + else + new.warehouseid = GetCurrentWarehouseId(); + mirroring_sanity_check(MASTER_ONLY | SUPERUSER, "gp_add_segment"); new.mode = GP_SEGMENT_CONFIGURATION_MODE_NOTINSYNC; @@ -472,7 +490,12 @@ gp_add_segment_mirror(PG_FUNCTION_ARGS) if (PG_ARGISNULL(4)) elog(ERROR, "datadir cannot be NULL"); new.datadir = TextDatumGetCString(PG_GETARG_DATUM(4)); - + + if (new.segindex == MASTER_CONTENT_ID) + new.warehouseid = InvalidOid; + else + new.warehouseid = GetCurrentWarehouseId(); + mirroring_sanity_check(MASTER_ONLY | SUPERUSER, "gp_add_segment_mirror"); new.dbid = get_availableDbId(); @@ -609,7 +632,9 @@ gp_add_master_standby(PG_FUNCTION_ARGS) config->address = TextDatumGetCString(PG_GETARG_TEXT_P(1)); config->datadir = TextDatumGetCString(PG_GETARG_TEXT_P(2)); - + + config->warehouseid = InvalidOid; + /* Use the new port number if specified */ if (PG_NARGS() > 3 && !PG_ARGISNULL(3)) config->port = PG_GETARG_INT32(3); @@ -665,7 +690,7 @@ catalog_activate_standby(int16 standby_dbid, int16 master_dbid) Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(master_dbid)); - sscan = systable_beginscan(rel, GpSegmentConfigDbidIndexId, true, + sscan = systable_beginscan(rel, GpSegmentConfigDbidWarehouseIndexId, true, NULL, 1, &scankey); while ((tuple = systable_getnext(sscan)) != NULL) { @@ -682,7 +707,7 @@ catalog_activate_standby(int16 standby_dbid, int16 master_dbid) Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(standby_dbid)); - sscan = systable_beginscan(rel, GpSegmentConfigDbidIndexId, true, + sscan = systable_beginscan(rel, GpSegmentConfigDbidWarehouseIndexId, true, NULL, 1, &scankey); tuple = systable_getnext(sscan); @@ -830,16 +855,20 @@ gp_update_segment_configuration_mode_status(PG_FUNCTION_ARGS) /* we use AccessExclusiveLock to prevent races */ Relation rel = table_open(GpSegmentConfigRelationId, AccessExclusiveLock); HeapTuple tuple; - ScanKeyData scankey; + ScanKeyData scankey[2]; SysScanDesc sscan; /* now, set out rows for old standby. */ - ScanKeyInit(&scankey, + ScanKeyInit(&scankey[0], Anum_gp_segment_configuration_dbid, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); - sscan = systable_beginscan(rel, GpSegmentConfigDbidIndexId, true, - NULL, 1, &scankey); + ScanKeyInit(&scankey[1], + Anum_gp_segment_configuration_warehouseid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(GetCurrentWarehouseId())); + sscan = systable_beginscan(rel, GpSegmentConfigDbidWarehouseIndexId, true, + NULL, 2, scankey); tuple = systable_getnext(sscan); diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index abdc2567914..a4214ad0662 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -478,6 +478,8 @@ static int SecurityRestrictionContext = 0; /* We also remember if a SET ROLE is currently active */ static bool SetRoleIsActive = false; +static Oid CurrentWarehouseId = InvalidOid; + /* * GetUserId - get the current effective user ID. * @@ -963,6 +965,18 @@ GetUserNameFromId(Oid roleid, bool noerr) return result; } +Oid +GetCurrentWarehouseId(void) +{ + return CurrentWarehouseId; +} + +void +SetCurrentWarehouseId(Oid warehouseid) +{ + AssertArg(OidIsValid(warehouseid)); + CurrentWarehouseId = warehouseid; +} /*------------------------------------------------------------------------- * Interlock-file support diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index aea25234a23..e38a602d8a9 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1142,6 +1142,7 @@ static const pgsql_thing_t words_after_create[] = { {"USER", Query_for_list_of_roles " UNION SELECT 'MAPPING FOR'"}, {"USER MAPPING FOR", NULL, NULL, NULL}, {"VIEW", NULL, NULL, &Query_for_list_of_views}, + {"WAREHOUSE", NULL}, {NULL} /* end of list */ }; @@ -2735,6 +2736,10 @@ psql_completion(const char *text, int start, int end) Matches("CREATE", "TASK", MatchAny, "SCHEDULE", MatchAny, "USER", MatchAny)) COMPLETE_WITH("AS"); +/* CREATE WAREHOUSE */ + else if (Matches("CREATE", "WAREHOUSE", MatchAny)) + COMPLETE_WITH("WAREHOUSE_SIZE"); + /* CREATE SERVER */ else if (Matches("CREATE", "SERVER", MatchAny)) COMPLETE_WITH("TYPE", "VERSION", "FOREIGN DATA WRAPPER"); diff --git a/src/include/catalog/gp_segment_configuration.h b/src/include/catalog/gp_segment_configuration.h index 46ac37e02c2..1705924e23b 100644 --- a/src/include/catalog/gp_segment_configuration.h +++ b/src/include/catalog/gp_segment_configuration.h @@ -58,6 +58,7 @@ CATALOG(gp_segment_configuration,7026,GpSegmentConfigRelationId) BKI_SHARED_RELA text address; text datadir; + Oid warehouseid BKI_DEFAULT(0); #endif } FormData_gp_segment_configuration; diff --git a/src/include/catalog/gp_segment_configuration_indexing.h b/src/include/catalog/gp_segment_configuration_indexing.h index 4d530aa1e22..7d72782e6d4 100644 --- a/src/include/catalog/gp_segment_configuration_indexing.h +++ b/src/include/catalog/gp_segment_configuration_indexing.h @@ -14,9 +14,9 @@ #include "catalog/genbki.h" -DECLARE_UNIQUE_INDEX(gp_segment_config_content_preferred_role_index, 7139, on gp_segment_configuration using btree(content int2_ops, preferred_role char_ops)); -#define GpSegmentConfigContentPreferred_roleIndexId 7139 -DECLARE_UNIQUE_INDEX(gp_segment_config_dbid_index, 7140, on gp_segment_configuration using btree(dbid int2_ops)); -#define GpSegmentConfigDbidIndexId 7140 +DECLARE_UNIQUE_INDEX(gp_segment_config_content_preferred_role_warehouse_index, 7139, on gp_segment_configuration using btree(content int2_ops, preferred_role char_ops, warehouseid oid_ops)); +#define GpSegmentConfigContentPreferred_roleWarehouseIndexId 7139 +DECLARE_UNIQUE_INDEX(gp_segment_config_dbid_warehouse_index, 7140, on gp_segment_configuration using btree(dbid int2_ops, warehouseid oid_ops)); +#define GpSegmentConfigDbidWarehouseIndexId 7140 #endif // GP_SEGMENT_CONFIGURATION_INDEXING_H \ No newline at end of file diff --git a/src/include/catalog/gp_warehouse.h b/src/include/catalog/gp_warehouse.h new file mode 100644 index 00000000000..87646361569 --- /dev/null +++ b/src/include/catalog/gp_warehouse.h @@ -0,0 +1,23 @@ +#ifndef GP_WAREHOUSE_H +#define GP_WAREHOUSE_H + +#include "catalog/genbki.h" +#include "catalog/gp_warehouse_d.h" + +/* + * Defines for gp_version_at_initdb table + */ +CATALOG(gp_warehouse,8690,GpWarehouseRelationId) BKI_SHARED_RELATION +{ + Oid oid; /* oid */ + text warehouse_name; /* warehouse name */ +} FormData_gp_warehouse; + +typedef FormData_gp_warehouse *Form_gp_warehouse; + +DECLARE_UNIQUE_INDEX(gp_warehouse_oid_index, 8086, on gp_warehouse using btree(oid oid_ops)); +#define GpWarehouseOidIndexId 8086 +DECLARE_UNIQUE_INDEX(gp_warehouse_name_index, 8059, on gp_warehouse using btree(warehouse_name text_ops)); +#define GpWarehouseNameIndexId 8059 + +#endif /* GP_WAREHOUSE_H */ diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index d67953e5126..07e375dfea0 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -460,6 +460,8 @@ extern void InitializeSessionUserIdStandalone(void); extern void SetSessionAuthorization(Oid userid, bool is_superuser); extern Oid GetCurrentRoleId(void); extern void SetCurrentRoleId(Oid roleid, bool is_superuser); +extern Oid GetCurrentWarehouseId(void); +extern void SetCurrentWarehouseId(Oid warehouseid); /* in utils/misc/superuser.c */ extern bool superuser(void); /* current user is superuser */ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 89469a8c316..0912902eb21 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -542,6 +542,8 @@ typedef enum NodeTag T_GpDropPartitionCmd, T_GpSplitPartitionCmd, T_GpAlterPartitionCmd, + T_CreateWarehouseStmt, + T_DropWarehouseStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 77e60a68765..4af6cbc1f9f 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -4260,4 +4260,21 @@ typedef struct RetrieveStmt bool is_all; } RetrieveStmt; +/* ---------------------- + * Warehouse Statement + * ---------------------- + */ +typedef struct CreateWarehouseStmt +{ + NodeTag type; + char *whname; + List *options; /* List of DefElem nodes */ +} CreateWarehouseStmt; + +typedef struct DropWarehouseStmt +{ + NodeTag type; + char *whname; +} DropWarehouseStmt; + #endif /* PARSENODES_H */ diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 3df64f49ca1..a6e840fc4fe 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -520,6 +520,8 @@ PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("warehouse", WAREHOUSE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("warehouse_size", WAREHOUSE_SIZE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("web", WEB, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, AS_LABEL) diff --git a/src/include/postmaster/fts_comm.h b/src/include/postmaster/fts_comm.h index 765ad45e994..16fc53247c2 100644 --- a/src/include/postmaster/fts_comm.h +++ b/src/include/postmaster/fts_comm.h @@ -148,6 +148,7 @@ typedef struct GpSegConfigEntry char *hostname; /* name or ip address of host machine */ char *address; /* ip address of host machine */ char *datadir; /* absolute path to data directory on the host. */ + Oid warehouseid; /* additional cached info */ char *hostip; /* cached lookup of name */ diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index 42014da620f..a8806269fa6 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -120,4 +120,8 @@ extern bool LockTagIsTemp(const LOCKTAG *tag); extern void GxactLockTableInsert(DistributedTransactionId xid); extern void GxactLockTableWait(DistributedTransactionId xid); + +/* Lock a warehouse */ +extern void LockWarehouse(Oid warehouseOid, LOCKMODE lockmode); +extern void UnlockWarehouse(Oid warehouseOid, LOCKMODE lockmode); #endif /* LMGR_H */ diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index b70eea63d6e..5f77b5f942a 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -168,10 +168,11 @@ typedef enum LockTagType LOCKTAG_RESOURCE_QUEUE, /* ID info for resource queue is QUEUE ID */ LOCKTAG_DISTRIB_TRANSACTION,/* CDB: distributed transaction (for waiting for distributed xact done) */ LOCKTAG_USERLOCK, /* reserved for old contrib/userlock code */ - LOCKTAG_ADVISORY /* advisory user locks */ + LOCKTAG_ADVISORY, /* advisory user locks */ + LOCKTAG_WAREHOUSE /* warehouse locks */ } LockTagType; -#define LOCKTAG_LAST_TYPE LOCKTAG_ADVISORY +#define LOCKTAG_LAST_TYPE LOCKTAG_WAREHOUSE extern const char *const LockTagTypeNames[]; @@ -317,6 +318,14 @@ typedef struct LOCKTAG (locktag).locktag_type = LOCKTAG_RESOURCE_QUEUE, \ (locktag).locktag_lockmethodid = RESOURCE_LOCKMETHOD) +#define SET_LOCKTAG_WAREHOUSE(locktag,warehouseid) \ + ((locktag).locktag_field1 = (warehouseid), \ + (locktag).locktag_field2 = 0, \ + (locktag).locktag_field3 = 0, \ + (locktag).locktag_field4 = 0, \ + (locktag).locktag_type = LOCKTAG_WAREHOUSE, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + /* * Per-locked-object lock information: * diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h index a6c36d31350..61469142633 100644 --- a/src/include/tcop/cmdtaglist.h +++ b/src/include/tcop/cmdtaglist.h @@ -135,6 +135,7 @@ PG_CMDTAG(CMDTAG_CREATE_TYPE, "CREATE TYPE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TASK, "CREATE TASK", true, false, false) PG_CMDTAG(CMDTAG_CREATE_USER_MAPPING, "CREATE USER MAPPING", true, false, false) PG_CMDTAG(CMDTAG_CREATE_VIEW, "CREATE VIEW", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_WAREHOUSE, "CREATE WAREHOUSE", true, false, false) PG_CMDTAG(CMDTAG_DEALLOCATE, "DEALLOCATE", false, false, false) PG_CMDTAG(CMDTAG_DEALLOCATE_ALL, "DEALLOCATE ALL", false, false, false) PG_CMDTAG(CMDTAG_DECLARE_CURSOR, "DECLARE CURSOR", false, false, false) @@ -201,6 +202,7 @@ PG_CMDTAG(CMDTAG_DROP_TRIGGER, "DROP TRIGGER", true, false, false) PG_CMDTAG(CMDTAG_DROP_TYPE, "DROP TYPE", true, false, false) PG_CMDTAG(CMDTAG_DROP_USER_MAPPING, "DROP USER MAPPING", true, false, false) PG_CMDTAG(CMDTAG_DROP_VIEW, "DROP VIEW", true, false, false) +PG_CMDTAG(CMDTAG_DROP_WAREHOUSE, "DROP WAREHOUSE", true, false, false) diff --git a/src/test/regress/expected/misc_sanity.out b/src/test/regress/expected/misc_sanity.out index 13947c53237..4f7ef1d12b7 100644 --- a/src/test/regress/expected/misc_sanity.out +++ b/src/test/regress/expected/misc_sanity.out @@ -105,6 +105,7 @@ ORDER BY 1, 2; --------------------------+--------------------+-------------- gp_configuration_history | desc | text gp_version_at_initdb | productversion | text + gp_warehouse | warehouse_name | text pg_attribute | attacl | aclitem[] pg_attribute | attfdwoptions | text[] pg_attribute | attmissingval | anyarray @@ -133,7 +134,7 @@ ORDER BY 1, 2; pg_task_run_history | return_message | text pg_task_run_history | status | text pg_task_run_history | username | text -(30 rows) +(31 rows) -- system catalogs without primary keys -- @@ -153,6 +154,7 @@ ORDER BY 1; gp_id gp_partition_template gp_version_at_initdb + gp_warehouse pg_appendonly pg_attribute_encoding pg_auth_time_constraint @@ -169,7 +171,7 @@ ORDER BY 1; pg_stat_last_operation pg_stat_last_shoperation pg_type_encoding -(22 rows) +(23 rows) -- system catalog unique indexes not wrapped in a constraint -- (There should be none.) diff --git a/src/test/regress/output/dispatch.source b/src/test/regress/output/dispatch.source index 109f6a2e8fa..d4c6ed0f383 100644 --- a/src/test/regress/output/dispatch.source +++ b/src/test/regress/output/dispatch.source @@ -894,8 +894,8 @@ SELECT gp_inject_fault('cdbcomponent_recycle_idle_qe_error', 'interrupt', dbid, (1 row) select * from gp_segment_configuration a, t13393 ,gp_segment_configuration b where a.dbid = t13393.tc1 limit 0; - dbid | content | role | preferred_role | mode | status | port | hostname | address | datadir | tc1 | dbid | content | role | preferred_role | mode | status | port | hostname | address | datadir -------+---------+------+----------------+------+--------+------+----------+---------+---------+-----+------+---------+------+----------------+------+--------+------+----------+---------+--------- + dbid | content | role | preferred_role | mode | status | port | hostname | address | datadir | warehouseid | tc1 | dbid | content | role | preferred_role | mode | status | port | hostname | address | datadir | warehouseid +------+---------+------+----------------+------+--------+------+----------+---------+---------+-------------+-----+------+---------+------+----------------+------+--------+------+----------+---------+---------+------------- (0 rows) SELECT gp_inject_fault('cdbcomponent_recycle_idle_qe_error', 'reset', dbid, current_setting('gp_session_id')::int)