/* * TypeRename * This renames a type * * Note: any associated array type is *not* renamed; caller must make * another call to handle that case. Currently this is only used for * renaming types associated with tables, for which there are no arrays. */ void TypeRename(Oid typeOid, const char *newTypeName) { Relation pg_type_desc; HeapTuple tuple; Form_pg_type form; cqContext *pcqCtx; cqContext cqc, cqc2; pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock); pcqCtx = caql_addrel(cqclr(&cqc), pg_type_desc); tuple = caql_getfirst( pcqCtx, cql("SELECT * FROM pg_type " " WHERE oid = :1 " " FOR UPDATE ", ObjectIdGetDatum(typeOid))); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type with OID \"%d\" does not exist", typeOid))); form = (Form_pg_type) GETSTRUCT(tuple); if (namestrcmp(&(form->typname), newTypeName)) { if (caql_getcount( caql_addrel(cqclr(&cqc2), pg_type_desc), cql("SELECT COUNT(*) FROM pg_type " " WHERE typname = :1 " " AND typnamespace = :2 ", CStringGetDatum((char *) newTypeName), ObjectIdGetDatum(form->typnamespace)))) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", newTypeName))); } namestrcpy(&(form->typname), newTypeName); caql_update_current(pcqCtx, tuple); /* update the system catalog indexes (implicit) */ } heap_freetuple(tuple); heap_close(pg_type_desc, RowExclusiveLock); }
/* * Removes the policy of a table from the gp_distribution_policy table * Does nothing if the policy doesn't exist. */ void GpPolicyRemove(Oid tbloid) { Relation gp_policy_rel; cqContext cqc; /* * Open and lock the gp_distribution_policy catalog. */ gp_policy_rel = heap_open(GpPolicyRelationId, RowExclusiveLock); /* Delete the policy entry from the catalog. */ (void) caql_getcount( caql_addrel(cqclr(&cqc), gp_policy_rel), cql("DELETE FROM gp_distribution_policy " " WHERE localoid = :1 ", ObjectIdGetDatum(tbloid))); /* * Close the gp_distribution_policy relcache entry without unlocking. * We have updated the catalog: consequently the lock must be held until * end of transaction. */ heap_close(gp_policy_rel, NoLock); } /* GpPolicyRemove */
/* * Remove the master standby. * * gp_remove_master_standby() * * Returns: * true upon success otherwise false */ Datum gp_remove_master_standby(PG_FUNCTION_ARGS) { int numDel; cqContext cqc; mirroring_sanity_check(SUPERUSER | MASTER_ONLY | UTILITY_MODE, "gp_remove_master_standby"); if (!standby_exists()) elog(ERROR, "no master standby defined"); Relation rel = heap_open(GpSegmentConfigRelationId, AccessExclusiveLock); numDel= caql_getcount(caql_addrel(cqclr(&cqc), rel), cql("DELETE FROM gp_segment_configuration " " WHERE role = :1", CharGetDatum(SEGMENT_ROLE_STANDBY_CONFIG))); elog(LOG, "Remove standby, count : %d.", numDel); heap_close(rel, NoLock); update_gp_master_mirroring("Not Configured"); PG_RETURN_BOOL(true); }
/* * Activate a standby. To do this, we need to change * * 1. Check that we're actually the standby * 2. Remove standby from gp_segment_configuration. * * gp_activate_standby() * * Returns: * true upon success, otherwise throws error. */ Datum gp_activate_standby(PG_FUNCTION_ARGS) { cqContext cqc; int numDel; mirroring_sanity_check(SUPERUSER | UTILITY_MODE | STANDBY_ONLY, PG_FUNCNAME_MACRO); if (!AmIStandby()) elog(ERROR, "%s must be run on the standby master", PG_FUNCNAME_MACRO); /* remove standby from gp_segment_configuration */ Relation rel = heap_open(GpSegmentConfigRelationId, AccessExclusiveLock); numDel= caql_getcount(caql_addrel(cqclr(&cqc), rel), cql("DELETE FROM gp_segment_configuration " " WHERE role = :1", CharGetDatum(SEGMENT_ROLE_STANDBY_CONFIG))); elog(LOG, "Remove standby while activating it, count : %d.", numDel); heap_close(rel, NoLock); /* done */ PG_RETURN_BOOL(true); }
/* * Removes the policy of a table from the gp_distribution_policy table * * Callers must check that there actually *is* a policy for the relation. */ void GpPolicyRemove(Oid tbloid) { Relation gp_policy_rel; cqContext cqc; /* * Open and lock the gp_distribution_policy catalog. */ gp_policy_rel = heap_open(GpPolicyRelationId, RowExclusiveLock); /* Delete the policy entry from the catalog. */ if (0 == caql_getcount( caql_addrel(cqclr(&cqc), gp_policy_rel), cql("DELETE FROM gp_distribution_policy " " WHERE localoid = :1 ", ObjectIdGetDatum(tbloid)))) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("distribution policy for relation \"%d\" does not exist", tbloid))); } /* * Close the gp_distribution_policy relcache entry without unlocking. * We have updated the catalog: consequently the lock must be held until * end of transaction. */ heap_close(gp_policy_rel, NoLock); } /* GpPolicyRemove */
void update_segment_status_by_id(uint32_t id, char status) { /* we use AccessExclusiveLock to prevent races */ Relation rel = heap_open(GpSegmentConfigRelationId, AccessExclusiveLock); HeapTuple tuple; cqContext cqc; cqContext *pcqCtx; Assert(status == 'u' || status == 'd'); pcqCtx = caql_beginscan(caql_addrel(cqclr(&cqc), rel), cql("SELECT * FROM gp_segment_configuration " " WHERE registration_order = :1 " " FOR UPDATE ", Int32GetDatum(id))); tuple = caql_getnext(pcqCtx); if (tuple != NULL) { if (((Form_gp_segment_configuration)GETSTRUCT(tuple))->status != status) { ((Form_gp_segment_configuration)GETSTRUCT(tuple))->status = status; caql_update_current(pcqCtx, tuple); } } else { elog(LOG, "Can not find segment id: %d when update its status", id); } caql_endscan(pcqCtx); heap_close(rel, NoLock); }
/* * GetFastSequences * * Get a list of consecutive sequence numbers. The starting sequence * number is the maximal value between 'lastsequence' + 1 and minSequence. * The length of the list is given. * * If there is not such an entry for objid in the table, create * one here. * * The existing entry for objid in the table is updated with a new * lastsequence value. */ int64 GetFastSequences(Oid objid, int64 objmod, int64 minSequence, int64 numSequences) { Relation gp_fastsequence_rel; TupleDesc tupleDesc; HeapTuple tuple; cqContext cqc; int64 firstSequence = minSequence; Datum lastSequenceDatum; int64 newLastSequence; gp_fastsequence_rel = heap_open(FastSequenceRelationId, RowExclusiveLock); tupleDesc = RelationGetDescr(gp_fastsequence_rel); tuple = caql_getfirst( caql_addrel(cqclr(&cqc), gp_fastsequence_rel), cql("SELECT * FROM gp_fastsequence " " WHERE objid = :1 " " AND objmod = :2 " " FOR UPDATE ", ObjectIdGetDatum(objid), Int64GetDatum(objmod))); if (!HeapTupleIsValid(tuple)) { newLastSequence = firstSequence + numSequences - 1; } else { bool isNull; lastSequenceDatum = heap_getattr(tuple, Anum_gp_fastsequence_last_sequence, tupleDesc, &isNull); if (isNull) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("got an invalid lastsequence number: NULL"))); if (DatumGetInt64(lastSequenceDatum) + 1 > firstSequence) firstSequence = DatumGetInt64(lastSequenceDatum) + 1; newLastSequence = firstSequence + numSequences - 1; } update_fastsequence(gp_fastsequence_rel, tuple, tupleDesc, objid, objmod, newLastSequence); if (HeapTupleIsValid(tuple)) { heap_freetuple(tuple); } /* Refer to the comment at the end of InsertFastSequenceEntry. */ heap_close(gp_fastsequence_rel, RowExclusiveLock); return firstSequence; }
/* * Add a master standby. * * gp_add_master_standby(hostname, address) * * Args: * hostname - as above * address - as above * * Returns: * dbid of the new standby */ Datum gp_add_master_standby(PG_FUNCTION_ARGS) { CdbComponentDatabaseInfo *master = NULL; Relation gprel; Datum values[Natts_gp_segment_configuration]; bool nulls[Natts_gp_segment_configuration]; HeapTuple tuple; cqContext cqc; cqContext *pcqCtx = NULL; if (PG_ARGISNULL(0)) elog(ERROR, "host name cannot be NULL"); if (PG_ARGISNULL(1)) elog(ERROR, "address cannot be NULL"); mirroring_sanity_check(MASTER_ONLY | UTILITY_MODE, "gp_add_master_standby"); if (standby_exists()) elog(ERROR, "only a single master standby may be defined"); /* master */ master = registration_order_get_dbinfo(MASTER_ORDER_ID); /* Lock exclusively to avoid concurrent changes */ gprel = heap_open(GpSegmentConfigRelationId, AccessExclusiveLock); pcqCtx = caql_beginscan( caql_addrel(cqclr(&cqc), gprel), cql("INSERT INTO gp_segment_configuration ", NULL)); MemSet(nulls, false, sizeof(nulls)); values[Anum_gp_segment_configuration_registration_order - 1] = Int32GetDatum(STANDBY_ORDER_ID); values[Anum_gp_segment_configuration_role - 1] = CharGetDatum(SEGMENT_ROLE_STANDBY_CONFIG); values[Anum_gp_segment_configuration_status - 1] = CharGetDatum('u'); values[Anum_gp_segment_configuration_port - 1] = Int32GetDatum(master->port); values[Anum_gp_segment_configuration_hostname - 1] = PG_GETARG_DATUM(0); values[Anum_gp_segment_configuration_address - 1] = PG_GETARG_DATUM(1); nulls[Anum_gp_segment_configuration_description - 1] = true; tuple = caql_form_tuple(pcqCtx, values, nulls); /* insert a new tuple */ caql_insert(pcqCtx, tuple); /* implicit update of index as well */ caql_endscan(pcqCtx); if(master) pfree(master); heap_close(gprel, NoLock); PG_RETURN_INT16(1); }
/* * This tests if non-equal predicates also use index scan. */ void test__caql_switch5(void **state) { const char *query = "SELECT * FROM pg_attribute " "WHERE attrelid = :1 and attnum > :2"; struct caql_hash_cookie *hash_cookie; cqContext context = {0}, *pCtx; Datum keys[] = {ObjectIdGetDatum(ProcedureRelationId), Int16GetDatum(0)}; cq_list *pcql = CaQL(query, 2, keys); RelationData dummyrel; SysScanDescData dummydesc; dummyrel.rd_id = AttributeRelationId; hash_cookie = cq_lookup(query, strlen(query), pcql); /* * Add explicit relation, and set indexOK = true and syscache = false. */ pCtx = caql_addrel(cqclr(&context), &dummyrel); pCtx = caql_indexOK(pCtx, true); pCtx = caql_syscache(pCtx, false); /* setup ScanKeyInit */ expect__ScanKeyInit(NULL, false, Anum_pg_attribute_attrelid, true, BTEqualStrategyNumber, true, F_OIDEQ, true, NULL, false); /* setup ScanKeyInit */ expect__ScanKeyInit(NULL, false, Anum_pg_attribute_attnum, true, BTGreaterStrategyNumber, true, F_INT2GT, true, NULL, false); /* setup systable_beginscan */ expect__systable_beginscan(&dummyrel, true, AttributeRelidNumIndexId, true, true, true, SnapshotNow, true, 2, true, NULL, false, &dummydesc); pCtx = caql_switch(hash_cookie, pCtx, pcql); assert_true(pCtx != NULL); assert_true(pCtx->cq_sysScan == &dummydesc); assert_true(pCtx->cq_heap_rel == &dummyrel); assert_false(pCtx->cq_usesyscache); assert_true(pCtx->cq_useidxOK); }
/* * SetRelationRuleStatus * Set the value of the relation's relhasrules field in pg_class; * if the relation is becoming a view, also adjust its relkind. * * NOTE: caller must be holding an appropriate lock on the relation. * * NOTE: an important side-effect of this operation is that an SI invalidation * message is sent out to all backends --- including me --- causing relcache * entries to be flushed or updated with the new set of rules for the table. * This must happen even if we find that no change is needed in the pg_class * row. */ void SetRelationRuleStatus(Oid relationId, bool relHasRules, bool relIsBecomingView) { Relation relationRelation; HeapTuple tuple; Form_pg_class classForm; cqContext cqc; cqContext *pcqCtx; /* * Find the tuple to update in pg_class, using syscache for the lookup. */ relationRelation = heap_open(RelationRelationId, RowExclusiveLock); pcqCtx = caql_addrel(cqclr(&cqc), relationRelation); tuple = caql_getfirst( pcqCtx, cql("SELECT * FROM pg_class " " WHERE oid = :1 " " FOR UPDATE ", ObjectIdGetDatum(relationId))); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relationId); classForm = (Form_pg_class) GETSTRUCT(tuple); if (classForm->relhasrules != relHasRules || (relIsBecomingView && classForm->relkind != RELKIND_VIEW)) { /* Do the update */ classForm->relhasrules = relHasRules; if (relIsBecomingView) { classForm->relkind = RELKIND_VIEW; classForm->relstorage = RELSTORAGE_VIRTUAL; } caql_update_current(pcqCtx, tuple); /* implicit update of index */ } else { /* no need to change tuple, but force relcache rebuild anyway */ CacheInvalidateRelcacheByTuple(tuple); } heap_freetuple(tuple); heap_close(relationRelation, RowExclusiveLock); }
/* * IsErrorTable * * Returns true if relid is used as an error table, which has dependent object * that is an external table. Though it's not great we didn't have a clear * definition of Error Table, it satisfies the current requirements. */ bool IsErrorTable(Relation rel) { cqContext *pcqCtx, *pcqCtxExt, ctxExt; HeapTuple tup; Relation extrel; bool result = false; /* fast path to quick check */ if (!RelationIsHeap(rel)) return false; /* * Otherwise, go deeper and play with pg_depend... */ pcqCtx = caql_beginscan(NULL, cql("SELECT * FROM pg_depend " " WHERE refclassid = :1 " " AND refobjid = :2 " " AND refobjsubid = :3 ", ObjectIdGetDatum(RelationRelationId), ObjectIdGetDatum(RelationGetRelid(rel)), Int32GetDatum(0))); extrel = relation_open(ExtTableRelationId, AccessShareLock); pcqCtxExt = caql_addrel(cqclr(&ctxExt), extrel); while (HeapTupleIsValid(tup = caql_getnext(pcqCtx))) { Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(tup); Oid fmterrtbl; fmterrtbl = caql_getoid(pcqCtxExt, cql("SELECT fmterrtbl FROM pg_exttable " " WHERE reloid = :1", ObjectIdGetDatum(dep->objid))); if (RelationGetRelid(rel) == fmterrtbl) { result = true; break; } } relation_close(extrel, AccessShareLock); caql_endscan(pcqCtx); return result; }
/* * Get datum representations of the attoptions field in pg_attribute_encoding * for the given relation. */ Datum * get_rel_attoptions(Oid relid, AttrNumber max_attno) { Form_pg_attribute attform; HeapTuple tuple; cqContext cqc; cqContext *pcqCtx; Datum *dats; Relation pgae = heap_open(AttributeEncodingRelationId, AccessShareLock); /* used for attbyval and len below */ attform = pgae->rd_att->attrs[Anum_pg_attribute_encoding_attoptions - 1]; dats = palloc0(max_attno * sizeof(Datum)); pcqCtx = caql_beginscan( caql_addrel(cqclr(&cqc), pgae), cql("SELECT * FROM pg_attribute_encoding " " WHERE attrelid = :1 ", ObjectIdGetDatum(relid))); while (HeapTupleIsValid(tuple = caql_getnext(pcqCtx))) { Form_pg_attribute_encoding a = (Form_pg_attribute_encoding)GETSTRUCT(tuple); int16 attnum = a->attnum; Datum attoptions; bool isnull; Insist(attnum > 0 && attnum <= max_attno); attoptions = heap_getattr(tuple, Anum_pg_attribute_encoding_attoptions, RelationGetDescr(pgae), &isnull); Insist(!isnull); dats[attnum - 1] = datumCopy(attoptions, attform->attbyval, attform->attlen); } caql_endscan(pcqCtx); heap_close(pgae, AccessShareLock); return dats; }
/* convert schema type from old dboid to newdboid */ bool convert_schema_type(char *schema, Oid oldDboid, Oid newDboid) { Assert(NSPDBOID_CURRENT == oldDboid || NSPDBOID_CURRENT == newDboid); Assert(HcatalogDbOid == oldDboid || HcatalogDbOid == newDboid); Assert(newDboid != oldDboid); /* create tuples for pg_class table */ HeapTuple nsptup = NULL; HeapTuple copytup = NULL; cqContext cqc; Assert(Gp_role != GP_ROLE_EXECUTE); Relation rel = heap_open(NamespaceRelationId, RowExclusiveLock); cqContext *pcqCtx = caql_addrel(cqclr(&cqc), rel); nsptup = caql_getfirst( pcqCtx, cql("SELECT * FROM pg_namespace " " WHERE nspname = :1 and nspdboid = :2", CStringGetDatum(schema), ObjectIdGetDatum(oldDboid))); if (!HeapTupleIsValid(nsptup)) { heap_close(rel, NoLock); return false; } Datum values[Natts_pg_namespace]; bool nulls[Natts_pg_namespace]; bool replaces[Natts_pg_namespace]; MemSet(values, 0, sizeof(values)); MemSet(nulls, false, sizeof(nulls)); MemSet(replaces, false, sizeof(replaces)); replaces[Anum_pg_namespace_nspdboid - 1] = true; values[Anum_pg_namespace_nspdboid - 1] = newDboid; copytup = caql_modify_current(pcqCtx, values, nulls, replaces); caql_update_current(pcqCtx, copytup); heap_close(rel, NoLock); heap_freetuple(copytup); return true; }
/* * Test whether given name is currently used as a constraint name * for the given object (relation or domain). * * This is used to decide whether to accept a user-specified constraint name. * It is deliberately not the same test as ChooseConstraintName uses to decide * whether an auto-generated name is OK: here, we will allow it unless there * is an identical constraint name in use *on the same object*. * * NB: Caller should hold exclusive lock on the given object, else * this test can be fooled by concurrent additions. */ bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, Oid objNamespace, const char *conname) { bool found; Relation conDesc; HeapTuple tup; cqContext *pcqCtx; cqContext cqc; conDesc = heap_open(ConstraintRelationId, AccessShareLock); found = false; pcqCtx = caql_beginscan( caql_addrel(cqclr(&cqc), conDesc), cql("SELECT * FROM pg_constraint " " WHERE conname = :1 " " AND connamespace = :2 ", CStringGetDatum((char *) conname), ObjectIdGetDatum(objNamespace))); while (HeapTupleIsValid(tup = caql_getnext(pcqCtx))) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup); if (conCat == CONSTRAINT_RELATION && con->conrelid == objId) { found = true; break; } else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId) { found = true; break; } } caql_endscan(pcqCtx); heap_close(conDesc, AccessShareLock); return found; }
/* ---------------------------------------------------------------- * caql_begin_CacheList() * Return a catclist * * In general, catquery will choose the syscache when the cql * statement contains an equality predicate on *all* of the syscache * primary key index columns, eg: * * cql("SELECT * FROM pg_amop WHERE amopopr = :1 and amopclaid = :2 ") * * will use the AMOPOPID syscache with index * AccessMethodOperatorIndexId. However, the cql statement for a * list-search requires an equality predicate on a subset of the * initial columns of the index, with *all* of the index columns * specified in an ORDER BY clause, eg: * * cql("SELECT * FROM pg_amop WHERE amopopr = :1 " * " ORDER BY amopopr, amopclaid ") * * will use a syscache list-search if this cql statement is an * argument to caql_begin_CacheList(). However, the syscache will * *not* be used for this statement if it is supplied for * caql_beginscan(), since SearchSysCache() can only return (at most) * a single tuple. * * NOTE: caql_begin_CacheList() will assert (Insist!) at runtime if * the cql statement does not map to a syscache lookup. * NOTE: it may be possible to "collapse" this API into the existing * beginscan/getnext/endscan. * ---------------------------------------------------------------- */ struct catclist * caql_begin_CacheList(cqContext *pCtx0, cq_list *pcql) { const char* caql_str = pcql->caqlStr; const char* filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ Assert(!pchn->bUpdate); /* UPDATE not allowed */ Assert(!pchn->bDelete); /* DELETE not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); /* NOTE: for case of cache list search, we must use syscache */ pCtx->cq_bCacheList = true; pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ /* NOTE: must use the SysCache */ Insist (pCtx->cq_usesyscache); caql_heapclose(pCtx); return SearchSysCacheKeyArrayList(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); }
/* * Master function to remove a segment from all catalogs */ static void remove_segment(int16 order) { cqContext cqc; int numDel; if(order == MASTER_ORDER_ID || order == STANDBY_ORDER_ID) return; /* remove this segment from gp_segment_configuration */ Relation rel = heap_open(GpSegmentConfigRelationId, AccessExclusiveLock); numDel= caql_getcount(caql_addrel(cqclr(&cqc), rel), cql("DELETE FROM gp_segment_configuration " " WHERE registration_order = :1", Int16GetDatum(order))); elog(LOG, "Remove segment successfully! Count : %d. Registration order : %d", numDel, order); heap_close(rel, NoLock); }
void ExtProtocolDeleteByOid(Oid protOid) { Relation rel; cqContext cqc; /* * Search pg_extprotocol. We use a heapscan here even though there is an * index on oid, on the theory that pg_extprotocol will usually have just a * few entries and so an indexed lookup is a waste of effort. */ rel = heap_open(ExtprotocolRelationId, RowExclusiveLock); if (0 == caql_getcount( caql_addrel(cqclr(&cqc), rel), cql("DELETE FROM pg_extprotocol " " WHERE oid = :1 ", ObjectIdGetDatum(protOid)))) { elog(ERROR, "protocol %u could not be found", protOid); } heap_close(rel, NoLock); }
/* * Sets the policy of a table into the gp_distribution_policy table * from a GpPolicy structure. * */ void GpPolicyReplace(Oid tbloid, const GpPolicy *policy) { Relation gp_policy_rel; HeapTuple gp_policy_tuple = NULL; cqContext cqc; cqContext *pcqCtx; ArrayType *attrnums; bool nulls[2]; Datum values[2]; bool repl[2]; Insist(policy->ptype == POLICYTYPE_PARTITIONED); /* * Open and lock the gp_distribution_policy catalog. */ gp_policy_rel = heap_open(GpPolicyRelationId, RowExclusiveLock); pcqCtx = caql_addrel(cqclr(&cqc), gp_policy_rel); /* * Convert C arrays into Postgres arrays. */ if (policy->nattrs > 0) { int i; Datum *akey; akey = (Datum *) palloc(policy->nattrs * sizeof(Datum)); for (i = 0; i < policy->nattrs; i++) akey[i] = Int16GetDatum(policy->attrs[i]); attrnums = construct_array(akey, policy->nattrs, INT2OID, 2, true, 's'); } else { attrnums = NULL; } nulls[0] = false; nulls[1] = false; values[0] = ObjectIdGetDatum(tbloid); if (attrnums) values[1] = PointerGetDatum(attrnums); else nulls[1] = true; repl[0] = false; repl[1] = true; /* * Select by value of the localoid field */ gp_policy_tuple = caql_getfirst( pcqCtx, cql("SELECT * FROM gp_distribution_policy " " WHERE localoid = :1 " " FOR UPDATE ", ObjectIdGetDatum(tbloid))); /* * Read first (and only ) tuple */ if (HeapTupleIsValid(gp_policy_tuple)) { HeapTuple newtuple = caql_modify_current(pcqCtx, values, nulls, repl); caql_update_current(pcqCtx, newtuple); /* and Update indexes (implicit) */ heap_freetuple(newtuple); } else { gp_policy_tuple = caql_form_tuple(pcqCtx, values, nulls); caql_insert(pcqCtx, gp_policy_tuple); /* and Update indexes (implicit) */ } /* * Close the gp_distribution_policy relcache entry without unlocking. * We have updated the catalog: consequently the lock must be held until * end of transaction. */ heap_close(gp_policy_rel, NoLock); } /* GpPolicyReplace */
/* * get dbinfo by role * There should be only one master in gp_segment_configuration table, one standby at most. */ CdbComponentDatabaseInfo * role_get_dbinfo(char role) { HeapTuple tuple; Relation rel; cqContext cqc; bool bOnly; CdbComponentDatabaseInfo *i = NULL; Assert(role == SEGMENT_ROLE_PRIMARY || role == SEGMENT_ROLE_MASTER_CONFIG || role == SEGMENT_ROLE_STANDBY_CONFIG); /* * Can only run on a master node, this restriction is due to the reliance * on the gp_segment_configuration table. This may be able to be relaxed * by switching to a different method of checking. */ if (!AmActiveMaster() && !AmStandbyMaster()) elog(ERROR, "role_get_dbinfo() executed on execution segment"); rel = heap_open(GpSegmentConfigRelationId, AccessShareLock); tuple = caql_getfirst_only( caql_addrel(cqclr(&cqc), rel), &bOnly, cql("SELECT * FROM gp_segment_configuration " " WHERE role = :1 ", CharGetDatum(role))); if (HeapTupleIsValid(tuple)) { Datum attr; bool isNull; i = palloc(sizeof(CdbComponentDatabaseInfo)); /* * 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); /* * hostname */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_hostname, RelationGetDescr(rel), &isNull); Assert(!isNull); i->hostname = TextDatumGetCString(attr); /* * 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); } else { elog(ERROR, "could not find configuration entry for role %c", role); } heap_close(rel, NoLock); return i; }
CdbComponentDatabaseInfo * dbid_get_dbinfo(int16 dbid) { HeapTuple tuple; Relation rel; cqContext cqc; bool bOnly; CdbComponentDatabaseInfo *i = NULL; /* * Can only run on a master node, this restriction is due to the reliance * on the gp_segment_configuration table. This may be able to be relaxed * by switching to a different method of checking. */ if (GpIdentity.segindex != MASTER_CONTENT_ID) elog(ERROR, "dbid_get_dbinfo() executed on execution segment"); rel = heap_open(GpSegmentConfigRelationId, AccessShareLock); tuple = caql_getfirst_only( caql_addrel(cqclr(&cqc), rel), &bOnly, cql("SELECT * FROM gp_segment_configuration " " WHERE dbid = :1 ", Int16GetDatum(dbid))); if (HeapTupleIsValid(tuple)) { Datum attr; bool isNull; i = palloc(sizeof(CdbComponentDatabaseInfo)); /* * dbid */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_dbid, RelationGetDescr(rel), &isNull); Assert(!isNull); i->dbid = DatumGetInt16(attr); /* * content */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_content, RelationGetDescr(rel), &isNull); Assert(!isNull); i->segindex = DatumGetInt16(attr); /* * role */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_role, RelationGetDescr(rel), &isNull); Assert(!isNull); i->role = DatumGetChar(attr); /* * preferred-role */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_preferred_role, RelationGetDescr(rel), &isNull); Assert(!isNull); i->preferred_role = DatumGetChar(attr); /* * mode */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_mode, RelationGetDescr(rel), &isNull); Assert(!isNull); i->mode = DatumGetChar(attr); /* * status */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_status, RelationGetDescr(rel), &isNull); Assert(!isNull); i->status = DatumGetChar(attr); /* * hostname */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_hostname, RelationGetDescr(rel), &isNull); Assert(!isNull); i->hostname = TextDatumGetCString(attr); /* * 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); /* * Filerep_port */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_replication_port, RelationGetDescr(rel), &isNull); if (!isNull) i->filerep_port = DatumGetInt32(attr); else i->filerep_port = -1; Assert(bOnly); /* should be only 1 */ } else { elog(ERROR, "could not find configuration entry for dbid %i", dbid); } heap_close(rel, NoLock); return i; }
/* * get dbinfo by registration_order */ CdbComponentDatabaseInfo * registration_order_get_dbinfo(int32 order) { HeapTuple tuple; Relation rel; bool bOnly; CdbComponentDatabaseInfo *i = NULL; cqContext cqc; if (!AmActiveMaster() && !AmStandbyMaster()) elog(ERROR, "registration_order_get_dbinfo() executed on execution segment"); rel = heap_open(GpSegmentConfigRelationId, AccessShareLock); tuple = caql_getfirst_only( caql_addrel(cqclr(&cqc), rel), &bOnly, cql("SELECT * FROM gp_segment_configuration " " WHERE registration_order = :1 ", Int32GetDatum(order))); if (HeapTupleIsValid(tuple)) { Datum attr; bool isNull; i = palloc(sizeof(CdbComponentDatabaseInfo)); /* * 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); /* * hostname */ attr = heap_getattr(tuple, Anum_gp_segment_configuration_hostname, RelationGetDescr(rel), &isNull); Assert(!isNull); i->hostname = TextDatumGetCString(attr); /* * 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); } else { heap_close(rel, NoLock); elog(ERROR, "could not find configuration entry for registration_order %c", order); } heap_close(rel, NoLock); return i; }
/* ---------------------------------------------------------------- * caql_getcount() * Perform COUNT(*) or DELETE * ---------------------------------------------------------------- */ int caql_getcount(cqContext *pCtx0, cq_list *pcql) { const char* caql_str = pcql->caqlStr; const char* filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple; Relation rel; int ii = 0; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ rel = pCtx->cq_heap_rel; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); if (HeapTupleIsValid(tuple)) { ii++; pCtx->cq_lasttup = tuple; if (pchn->bDelete) simple_heap_delete(rel, &tuple->t_self); ReleaseSysCache(tuple); /* only one */ } caql_heapclose(pCtx); return (ii); } while (HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))) { if (HeapTupleIsValid(tuple) && pchn->bDelete) { pCtx->cq_lasttup = tuple; if (pchn->bDelete) simple_heap_delete(rel, &tuple->t_self); } ii++; } systable_endscan(pCtx->cq_sysScan); caql_heapclose(pCtx); return (ii); }
/* ---------------------------------------------------------------- * caql_getfirst_only() * Return a copy the first tuple, pallocd in the current memory context, * and end the scan. Clients should heap_freetuple() as necessary. * If pbOnly is not NULL, return TRUE if a second tuple is not found, * else return FALSE * NOTE: this function will return NULL if no tuples satisfy the * caql predicate -- use HeapTupleIsValid() to detect this condition. * ---------------------------------------------------------------- */ HeapTuple caql_getfirst_only(cqContext *pCtx0, bool *pbOnly, cq_list *pcql) { const char* caql_str = pcql->caqlStr; const char* filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple, newTup = NULL; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ if (pbOnly) *pbOnly = true; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); if (HeapTupleIsValid(tuple)) { newTup = heap_copytuple(tuple); ReleaseSysCache(tuple); /* only one */ } caql_heapclose(pCtx); pCtx->cq_lasttup = newTup; /* need this for update/delete */ return (newTup); } if (HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))) { /* always copy the tuple, because the endscan releases tup memory */ newTup = heap_copytuple(tuple); if (pbOnly) { *pbOnly = !(HeapTupleIsValid(systable_getnext(pCtx->cq_sysScan))); } } systable_endscan(pCtx->cq_sysScan); caql_heapclose(pCtx); pCtx->cq_lasttup = newTup; /* need this for update/delete */ return (newTup); }
/* ---------------------------------------------------------------- * caql_getoid_only() * Return the oid of the first tuple and end the scan * If pbOnly is not NULL, return TRUE if a second tuple is not found, * else return FALSE * ---------------------------------------------------------------- */ Oid caql_getoid_only(cqContext *pCtx0, bool *pbOnly, cq_list *pcql) { const char *caql_str = pcql->caqlStr; const char *filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple; Oid result = InvalidOid; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ if (pbOnly) *pbOnly = true; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); if (HeapTupleIsValid(tuple)) { result = HeapTupleGetOid(tuple); ReleaseSysCache(tuple); /* only one */ } caql_heapclose(pCtx); return (result); } if (HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))) { result = HeapTupleGetOid(tuple); if (pbOnly) { *pbOnly = !(HeapTupleIsValid(tuple = systable_getnext(pCtx->cq_sysScan))); } } systable_endscan(pCtx->cq_sysScan); caql_heapclose(pCtx); return (result); }
/* ---------------------------------------------------------------- * caql_getcstring_plus() * Return a cstring column from the first tuple and end the scan. * ---------------------------------------------------------------- */ char *caql_getcstring_plus(cqContext *pCtx0, int *pFetchcount, bool *pbIsNull, cq_list *pcql) { const char *caql_str = pcql->caqlStr; const char *filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple; char *result = NULL; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ if (pFetchcount) *pFetchcount = 0; if (pbIsNull) *pbIsNull = true; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); } else { tuple = systable_getnext(pCtx->cq_sysScan); } if (HeapTupleIsValid(tuple)) { bool isnull; Datum d; if (pFetchcount) *pFetchcount = 1; d = caql_getattr_internal(pCtx, tuple, pchn->attnum, &isnull); if (!isnull) { switch (pchn->atttype) { case NAMEOID: result = DatumGetCString(DirectFunctionCall1(nameout, d)); break; case TEXTOID: result = DatumGetCString(DirectFunctionCall1(textout, d)); break; default: elog(ERROR, "column not a cstring: %s\nfile: %s, line %d", caql_str, filenam, lineno); } } if (pbIsNull) *pbIsNull = isnull; } /* end HeapTupleIsValid */ if (pCtx->cq_usesyscache) { if (HeapTupleIsValid(tuple)) ReleaseSysCache(tuple); } else { if (pFetchcount && HeapTupleIsValid(tuple)) { if (HeapTupleIsValid(systable_getnext(pCtx->cq_sysScan))) { *pFetchcount = 2; } } systable_endscan(pCtx->cq_sysScan); } caql_heapclose(pCtx); return (result); } /* end caql_getcstring_plus */
/* ---------------------------------------------------------------- * caql_getoid_plus() * Return an oid column from the first tuple and end the scan. * Note: this works for regproc columns as well, but you should cast * the output as RegProcedure. * ---------------------------------------------------------------- */ Oid caql_getoid_plus(cqContext *pCtx0, int *pFetchcount, bool *pbIsNull, cq_list *pcql) { const char *caql_str = pcql->caqlStr; const char *filenam = pcql->filename; int lineno = pcql->lineno; struct caql_hash_cookie *pchn = cq_lookup(caql_str, strlen(caql_str), pcql); cqContext *pCtx; cqContext cqc; HeapTuple tuple; Oid result = InvalidOid; if (NULL == pchn) elog(ERROR, "invalid caql string: %s\nfile: %s, line %d", caql_str, filenam, lineno); Assert(!pchn->bInsert); /* INSERT not allowed */ /* use the provided context, or provide a clean local ctx */ if (pCtx0) pCtx = pCtx0; else pCtx = cqclr(&cqc); pCtx = caql_switch(pchn, pCtx, pcql); /* NOTE: caql_switch frees the pcql */ if (pFetchcount) *pFetchcount = 0; if (pbIsNull) *pbIsNull = true; /* use the SysCache */ if (pCtx->cq_usesyscache) { tuple = SearchSysCacheKeyArray(pCtx->cq_cacheId, pCtx->cq_NumKeys, pCtx->cq_cacheKeys); } else { tuple = systable_getnext(pCtx->cq_sysScan); } if (HeapTupleIsValid(tuple)) { if (pFetchcount) *pFetchcount = 1; /* if attnum not set, (InvalidAttrNumber == 0) * use tuple oid, else extract oid from column * (includes ObjectIdAttributeNumber == -2) */ if (pchn->attnum <= InvalidAttrNumber) { if (pbIsNull) *pbIsNull = false; result = HeapTupleGetOid(tuple); } else /* find oid column */ { bool isnull; Datum d = caql_getattr_internal(pCtx, tuple, pchn->attnum, &isnull); if (!isnull) { switch (pchn->atttype) { case OIDOID: case REGPROCOID: result = DatumGetObjectId(d); break; default: elog(ERROR, "column not an oid: %s\nfile: %s, line %d", caql_str, filenam, lineno); } } if (pbIsNull) *pbIsNull = isnull; } } /* end HeapTupleIsValid */ if (pCtx->cq_usesyscache) { if (HeapTupleIsValid(tuple)) ReleaseSysCache(tuple); } else { if (pFetchcount && HeapTupleIsValid(tuple)) { if (HeapTupleIsValid(systable_getnext(pCtx->cq_sysScan))) { *pFetchcount = 2; } } systable_endscan(pCtx->cq_sysScan); } caql_heapclose(pCtx); return (result); } /* end caql_getoid_plus */
/* MPP-6923: */ static List * AlterResqueueCapabilityEntry( List *stmtOptIdList, Oid queueid, ListCell *initcell, bool bCreate) { ListCell *lc; List *elems = NIL; List *dropelems = NIL; List *dupcheck = NIL; HeapTuple tuple; cqContext *pcqCtx; cqContext cqc; Relation rel = NULL; bool bWithout = false; TupleDesc tupdesc = NULL; #ifdef USE_ASSERT_CHECKING { DefElem *defel = (DefElem *) lfirst(initcell); Assert(0 == strcmp(defel->defname, "withliststart")); } #endif initcell = lnext(initcell); /* walk the original list and build a list of valid entries */ for_each_cell(lc, initcell) { DefElem *defel = (DefElem *) lfirst(lc); Oid resTypeOid = InvalidOid; int resTypeInt = 0; List *pentry = NIL; Value *pKeyVal = NULL; Value *pStrVal = NULL; if (!bWithout && (strcmp(defel->defname, "withoutliststart") == 0)) { bWithout = true; rel = heap_open(ResourceTypeRelationId, RowExclusiveLock); tupdesc = RelationGetDescr(rel); goto L_loop_cont; } /* ignore the basic threshold entries -- should already be processed */ if (strcmp(defel->defname, "active_statements") == 0) goto L_loop_cont; if (strcmp(defel->defname, "max_cost") == 0) goto L_loop_cont; if (strcmp(defel->defname, "cost_overcommit") == 0) goto L_loop_cont; if (strcmp(defel->defname, "min_cost") == 0) goto L_loop_cont; if (!GetResourceTypeByName(defel->defname, &resTypeInt, &resTypeOid)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("option \"%s\" is not a valid resource type", defel->defname))); pKeyVal = makeString(defel->defname); /* WITHOUT clause value determined in pg_resourcetype */ if (!bWithout) pStrVal = makeString(defGetString(defel)); else { pStrVal = NULL; /* if NULL, delete entry from * pg_resqueuecapability */ pcqCtx = caql_beginscan( caql_addrel(cqclr(&cqc), rel), cql("SELECT * FROM pg_resourcetype" " WHERE restypid = :1 FOR UPDATE", Int16GetDatum(resTypeInt))); while (HeapTupleIsValid(tuple = caql_getnext(pcqCtx))) { text *shutoff_text = NULL; char *shutoff_str = NULL; Datum shutoff_datum; bool isnull = false; Form_pg_resourcetype rtyp = (Form_pg_resourcetype)GETSTRUCT(tuple); if (!rtyp->reshasdisable) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("option \"%s\" cannot be disabled", defel->defname))); } /* required type must have a default value if it can * be disabled */ if (!rtyp->reshasdefault) { if (!rtyp->resrequired) /* optional resource without a default is * turned off by removing entry from * pg_resqueuecapability */ break; else { /* XXX XXX */ Assert(0); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("required option \"%s\" cannot be disabled", defel->defname))); } } /* get the shutoff string */ shutoff_datum = heap_getattr(tuple, Anum_pg_resourcetype_resdisabledsetting, tupdesc, &isnull); Assert(!isnull); shutoff_text = DatumGetTextP(shutoff_datum); shutoff_str = DatumGetCString( DirectFunctionCall1( textout, PointerGetDatum(shutoff_text))); pStrVal = makeString(shutoff_str); break; } /* end while heaptuple is valid */ caql_endscan(pcqCtx); } /* check for duplicate key specifications */ if (list_member(dupcheck, pKeyVal)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant option for \"%s\"", defel->defname))); dupcheck = lappend(dupcheck, pKeyVal); pentry = list_make2( makeInteger(resTypeInt), pStrVal); /* list of lists - (resource type, resource setting) */ if (bWithout) { /* if the "without" entry has an "off" value, then treat * it as a regular "with" item and update it in * pg_resqueuecapability, else remove its entry */ if (!pStrVal) dropelems = lappend(dropelems, pentry); else elems = lappend(elems, pentry); } else elems = lappend(elems, pentry); L_loop_cont: resTypeInt = 0; /* make compiler happy */ }
/* * ExtProtocolCreateWithOid */ Oid ExtProtocolCreateWithOid(const char *protocolName, List *readfuncName, List *writefuncName, List *validatorfuncName, Oid protOid, bool trusted) { Relation rel; HeapTuple tup; bool nulls[Natts_pg_extprotocol]; Datum values[Natts_pg_extprotocol]; Oid readfn = InvalidOid; Oid writefn = InvalidOid; Oid validatorfn = InvalidOid; NameData prtname; int i; ObjectAddress myself, referenced; Oid ownerId = GetUserId(); cqContext cqc; cqContext cqc2; cqContext *pcqCtx; /* sanity checks (caller should have caught these) */ if (!protocolName) elog(ERROR, "no protocol name supplied"); if (!readfuncName && !writefuncName) elog(ERROR, "protocol must have at least one of readfunc or writefunc"); /* * Until we add system protocols to pg_extprotocol, make sure no * protocols with the same name are created. */ if (strcasecmp(protocolName, "file") == 0 || strcasecmp(protocolName, "http") == 0 || strcasecmp(protocolName, "gpfdist") == 0 || strcasecmp(protocolName, "gpfdists") == 0) { ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("protocol \"%s\" already exists", protocolName), errhint("pick a different protocol name"))); } rel = heap_open(ExtprotocolRelationId, RowExclusiveLock); pcqCtx = caql_beginscan( caql_addrel(cqclr(&cqc), rel), cql("INSERT INTO pg_extprotocol", NULL)); /* make sure there is no existing protocol of same name */ if (caql_getcount( caql_addrel(cqclr(&cqc2), rel), cql("SELECT COUNT(*) FROM pg_extprotocol " " WHERE ptcname = :1 ", CStringGetDatum((char *) protocolName)))) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("protocol \"%s\" already exists", protocolName))); } /* * function checks: if supplied, check existence and correct signature in the catalog */ if (readfuncName) readfn = ValidateProtocolFunction(readfuncName, EXTPTC_FUNC_READER); if (writefuncName) writefn = ValidateProtocolFunction(writefuncName, EXTPTC_FUNC_WRITER); if (validatorfuncName) validatorfn = ValidateProtocolFunction(validatorfuncName, EXTPTC_FUNC_VALIDATOR); /* * Everything looks okay. Try to create the pg_extprotocol entry for the * protocol. (This could fail if there's already a conflicting entry.) */ /* initialize nulls and values */ for (i = 0; i < Natts_pg_extprotocol; i++) { nulls[i] = false; values[i] = (Datum) 0; } namestrcpy(&prtname, protocolName); values[Anum_pg_extprotocol_ptcname - 1] = NameGetDatum(&prtname); values[Anum_pg_extprotocol_ptcreadfn - 1] = ObjectIdGetDatum(readfn); values[Anum_pg_extprotocol_ptcwritefn - 1] = ObjectIdGetDatum(writefn); values[Anum_pg_extprotocol_ptcvalidatorfn - 1] = ObjectIdGetDatum(validatorfn); values[Anum_pg_extprotocol_ptcowner - 1] = ObjectIdGetDatum(ownerId); values[Anum_pg_extprotocol_ptctrusted - 1] = BoolGetDatum(trusted); nulls[Anum_pg_extprotocol_ptcacl - 1] = true; tup = caql_form_tuple(pcqCtx, values, nulls); if (protOid != (Oid) 0) HeapTupleSetOid(tup, protOid); /* insert a new tuple */ protOid = caql_insert(pcqCtx, tup); /* implicit update of index as well */ caql_endscan(pcqCtx); heap_close(rel, RowExclusiveLock); /* * Create dependencies for the protocol */ myself.classId = ExtprotocolRelationId; myself.objectId = protOid; myself.objectSubId = 0; /* Depends on read function, if any */ if (OidIsValid(readfn)) { referenced.classId = ProcedureRelationId; referenced.objectId = readfn; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Depends on write function, if any */ if (OidIsValid(writefn)) { referenced.classId = ProcedureRelationId; referenced.objectId = writefn; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* dependency on owner */ recordDependencyOnOwner(ExtprotocolRelationId, protOid, GetUserId()); return protOid; }
/* * Rename conversion */ void RenameConversion(List *name, const char *newname) { Oid conversionOid; Oid namespaceOid; HeapTuple tup; Relation rel; AclResult aclresult; cqContext cqc2; cqContext cqc; cqContext *pcqCtx; rel = heap_open(ConversionRelationId, RowExclusiveLock); conversionOid = FindConversionByName(name); if (!OidIsValid(conversionOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("conversion \"%s\" does not exist", NameListToString(name)))); pcqCtx = caql_addrel(cqclr(&cqc), rel); tup = caql_getfirst( pcqCtx, cql("SELECT * FROM pg_conversion " " WHERE oid = :1 " " FOR UPDATE ", ObjectIdGetDatum(conversionOid))); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for conversion %u", conversionOid); namespaceOid = ((Form_pg_conversion) GETSTRUCT(tup))->connamespace; /* make sure the new name doesn't exist */ if (caql_getcount( caql_addrel(cqclr(&cqc2), rel), cql("SELECT COUNT(*) FROM pg_conversion " " WHERE conname = :1 " " AND connamespace = :2 ", CStringGetDatum((char *) newname), ObjectIdGetDatum(namespaceOid)))) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("conversion \"%s\" already exists in schema \"%s\"", newname, get_namespace_name(namespaceOid)))); } /* must be owner */ if (!pg_conversion_ownercheck(conversionOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, NameListToString(name)); /* must have CREATE privilege on namespace */ aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceOid)); /* rename */ namestrcpy(&(((Form_pg_conversion) GETSTRUCT(tup))->conname), newname); caql_update_current(pcqCtx, tup); /* implicit update of index as well */ heap_close(rel, NoLock); heap_freetuple(tup); }
/* * AlterConversionOwner_internal * * Internal routine for changing the owner. rel must be pg_conversion, already * open and suitably locked; it will not be closed. */ static void AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId) { Form_pg_conversion convForm; HeapTuple tup; cqContext cqc; cqContext *pcqCtx; Assert(RelationGetRelid(rel) == ConversionRelationId); pcqCtx = caql_addrel(cqclr(&cqc), rel); tup = caql_getfirst( pcqCtx, cql("SELECT * FROM pg_conversion " " WHERE oid = :1 " " FOR UPDATE ", ObjectIdGetDatum(conversionOid))); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for conversion %u", conversionOid); convForm = (Form_pg_conversion) GETSTRUCT(tup); /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ if (convForm->conowner == newOwnerId) { heap_freetuple(tup); return; } AclResult aclresult; /* Superusers can always do it */ if (!superuser()) { /* Otherwise, must be owner of the existing object */ if (!pg_conversion_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, NameStr(convForm->conname)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); /* New owner must have CREATE privilege on namespace */ aclresult = pg_namespace_aclcheck(convForm->connamespace, newOwnerId, ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(convForm->connamespace)); } /* * Modify the owner --- okay to scribble on tup because it's a copy */ convForm->conowner = newOwnerId; caql_update_current(pcqCtx, tup); /* implicit update of index as well */ /* Update owner dependency reference */ changeDependencyOnOwner(ConversionRelationId, conversionOid, newOwnerId); heap_freetuple(tup); }