/* * Get the catalog entry for an exttable relation (from pg_exttable) */ ExtTableEntry* GetExtTableEntry(Oid relid) { ExtTableEntry *extentry; extentry = GetExtTableEntryIfExists(relid); if (!extentry) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("missing pg_exttable entry for relation \"%s\"", get_rel_name(relid)))); return extentry; }
/* * 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 */