/* * 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 */
/* * Sets the policy of a table into the gp_distribution_policy table * from a GpPolicy structure. * */ void GpPolicyStore(Oid tbloid, const GpPolicy *policy) { Relation gp_policy_rel; HeapTuple gp_policy_tuple = NULL; ArrayType *attrnums; bool nulls[2]; Datum values[2]; cqContext cqc; cqContext *pcqCtx; Insist(policy->ptype == POLICYTYPE_PARTITIONED); /* * Open and lock the gp_distribution_policy catalog. */ gp_policy_rel = heap_open(GpPolicyRelationId, RowExclusiveLock); pcqCtx = caql_beginscan( caql_addrel(cqclr(&cqc), gp_policy_rel), cql("INSERT INTO gp_distribution_policy ", NULL)); /* * 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; gp_policy_tuple = caql_form_tuple(pcqCtx, values, nulls); /* Insert tuple into the relation */ caql_insert(pcqCtx, gp_policy_tuple); /* implicit update of index as well*/ /* * Close the gp_distribution_policy relcache entry without unlocking. * We have updated the catalog: consequently the lock must be held until * end of transaction. */ caql_endscan(pcqCtx); heap_close(gp_policy_rel, NoLock); } /* GpPolicyStore */
/* * ConversionCreate * * Add a new tuple to pg_conversion. */ Oid ConversionCreate(const char *conname, Oid connamespace, Oid conowner, int32 conforencoding, int32 contoencoding, Oid conproc, bool def, Oid newOid) { int i; Relation rel; HeapTuple tup; bool nulls[Natts_pg_conversion]; Datum values[Natts_pg_conversion]; NameData cname; Oid oid; ObjectAddress myself, referenced; cqContext cqc; cqContext *pcqCtx; /* sanity checks */ if (!conname) elog(ERROR, "no conversion name supplied"); /* open pg_conversion */ rel = heap_open(ConversionRelationId, RowExclusiveLock); /* make sure there is no existing conversion of same name */ if (caql_getcount( caql_addrel(cqclr(&cqc), rel), cql("SELECT COUNT(*) FROM pg_conversion " " WHERE conname = :1 " " AND connamespace = :2 ", CStringGetDatum((char *) conname), ObjectIdGetDatum(connamespace)))) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("conversion \"%s\" already exists", conname))); } if (def) { /* * make sure there is no existing default <for encoding><to encoding> * pair in this name space */ if (FindDefaultConversion(connamespace, conforencoding, contoencoding)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("default conversion for %s to %s already exists", pg_encoding_to_char(conforencoding), pg_encoding_to_char(contoencoding)))); } pcqCtx = caql_beginscan( caql_addrel(cqclr(&cqc), rel), cql("INSERT INTO pg_conversion", NULL)); /* initialize nulls and values */ for (i = 0; i < Natts_pg_conversion; i++) { nulls[i] = false; values[i] = (Datum) 0; } /* form a tuple */ namestrcpy(&cname, conname); values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname); values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace); values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner); values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding); values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding); values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc); values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def); tup = caql_form_tuple(pcqCtx, values, nulls); if (newOid != 0) HeapTupleSetOid(tup, newOid); /* insert a new tuple */ oid = caql_insert(pcqCtx, tup); /* implicit update of index as well */ Assert(OidIsValid(oid)); myself.classId = ConversionRelationId; myself.objectId = HeapTupleGetOid(tup); myself.objectSubId = 0; /* create dependency on conversion procedure */ referenced.classId = ProcedureRelationId; referenced.objectId = conproc; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* create dependency on namespace */ referenced.classId = NamespaceRelationId; referenced.objectId = connamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* create dependency on owner */ recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup), conowner); heap_freetuple(tup); caql_endscan(pcqCtx); heap_close(rel, RowExclusiveLock); return oid; }
/* * GpPolicyFetch * * Looks up the distribution policy of given relation from * gp_distribution_policy table (or by implicit rules for external tables) * Returns an GpPolicy object, allocated in the specified context, containing * the information. * * The caller is responsible for passing in a valid relation oid. This * function does not check, and assigns a policy of type POLICYTYPE_ENTRY * for any oid not found in gp_distribution_policy. */ GpPolicy * GpPolicyFetch(MemoryContext mcxt, Oid tbloid) { GpPolicy *policy = NULL; /* The result */ Relation gp_policy_rel; cqContext cqc; HeapTuple gp_policy_tuple = NULL; /* * Skip if qExec or utility mode. */ if (Gp_role != GP_ROLE_DISPATCH) { policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(0)); policy->ptype = POLICYTYPE_ENTRY; policy->nattrs = 0; return policy; } /* * EXECUTE-type external tables have an "ON ..." specification, stored * in pg_exttable.location. See if it's "MASTER_ONLY". Other types of * external tables have a gp_distribution_policy row, like normal tables. */ if (get_rel_relstorage(tbloid) == RELSTORAGE_EXTERNAL) { /* * An external table really should have a pg_exttable entry, but * there's currently a transient state during creation of an external * table, where the pg_class entry has been created, and its loaded * into the relcache, before the pg_exttable entry has been created. * Silently ignore missing pg_exttable rows to cope with that. */ ExtTableEntry *e = GetExtTableEntryIfExists(tbloid); /* * Writeable external tables have gp_distribution_policy entries, * like regular tables. Readable external tables are implicitly * randomly distributed, except for "EXECUTE ... ON MASTER" ones. */ if (e && !e->iswritable) { if (e->command) { char *on_clause = (char *) strVal(linitial(e->locations)); if (strcmp(on_clause, "MASTER_ONLY") == 0) { policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(0)); policy->ptype = POLICYTYPE_ENTRY; policy->nattrs = 0; return policy; } } policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(0)); policy->ptype = POLICYTYPE_PARTITIONED; policy->nattrs = 0; return policy; } } /* * We need to read the gp_distribution_policy table */ gp_policy_rel = heap_open(GpPolicyRelationId, AccessShareLock); /* * Select by value of the localoid field */ gp_policy_tuple = caql_getfirst( caql_addrel(cqclr(&cqc), gp_policy_rel), cql("SELECT * FROM gp_distribution_policy " " WHERE localoid = :1 ", ObjectIdGetDatum(tbloid))); /* * Read first (and only) tuple */ if (HeapTupleIsValid(gp_policy_tuple)) { bool isNull; Datum attr; int i, nattrs = 0; int16 *attrnums = NULL; /* * Get the attributes on which to partition. */ attr = heap_getattr(gp_policy_tuple, Anum_gp_policy_attrnums, RelationGetDescr(gp_policy_rel), &isNull); /* * Get distribution keys only if this table has a policy. */ if(!isNull) { extract_INT2OID_array(attr, &nattrs, &attrnums); Assert(nattrs >= 0); } /* Create an GpPolicy object. */ policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(nattrs)); policy->ptype = POLICYTYPE_PARTITIONED; policy->nattrs = nattrs; for (i = 0; i < nattrs; i++) { policy->attrs[i] = attrnums[i]; } } /* * Cleanup the scan and relation objects. */ heap_close(gp_policy_rel, AccessShareLock); /* Interpret absence of a valid policy row as POLICYTYPE_ENTRY */ if (policy == NULL) { policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(0)); policy->ptype = POLICYTYPE_ENTRY; policy->nattrs = 0; } return policy; } /* GpPolicyFetch */
/* * 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 ", PointerGetDatum((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; }