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);
}
Beispiel #2
0
/*
 * 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);
}
/*
 * 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);
}
/* 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;
}
Beispiel #5
0
/* AddUpdResqueueCapabilityEntryInternal:
 *
 * Internal function to add a new entry to pg_resqueuecapability, or
 * update an existing one.  Key cols are queueid, restypint.  If
 * old_tuple is set (ie not InvalidOid), the update the ressetting column,
 * else insert a new row.
 *
 */
static 
List *
 AddUpdResqueueCapabilityEntryInternal(
								  cqContext		*pcqCtx,
								  List			*stmtOptIdList,
								  Oid			 queueid,
								  int			 resTypeInt,
								  char			*pResSetting,
								  Relation		 rel,
								  HeapTuple		 old_tuple)
{
	HeapTuple	new_tuple;
	Datum		values[Natts_pg_resqueuecapability];
	bool		isnull[Natts_pg_resqueuecapability];
	bool		new_record_repl[Natts_pg_resqueuecapability];

	MemSet(isnull, 0, sizeof(bool) * Natts_pg_resqueuecapability);
	MemSet(new_record_repl, 0, sizeof(bool) * Natts_pg_resqueuecapability);

	values[Anum_pg_resqueuecapability_resqueueid - 1]  = 
			ObjectIdGetDatum(queueid);
	values[Anum_pg_resqueuecapability_restypid - 1]   = resTypeInt;

	Assert(pResSetting);

	values[Anum_pg_resqueuecapability_ressetting - 1] = 
			CStringGetTextDatum(pResSetting);
	/* set this column to update */
	new_record_repl[Anum_pg_resqueuecapability_ressetting - 1]  = true;

	ValidateResqueueCapabilityEntry(resTypeInt, pResSetting);

	if (HeapTupleIsValid(old_tuple))
	{
		new_tuple = caql_modify_current(pcqCtx, values,
										isnull, new_record_repl);

		caql_update_current(pcqCtx, new_tuple);
		/* and Update indexes (implicit) */
	}
	else
	{
		Oid s1;

		new_tuple = caql_form_tuple(pcqCtx, values, isnull);

		/* MPP-11858: synchronize the oids for CREATE/ALTER options... */
		if ((Gp_role != GP_ROLE_DISPATCH) && list_length(stmtOptIdList))
		{
			Oid s2 = list_nth_oid(stmtOptIdList, 0);
			stmtOptIdList = list_delete_first(stmtOptIdList);

			if (OidIsValid(s2))
				HeapTupleSetOid(new_tuple, s2);
		}

		s1 = caql_insert(pcqCtx, new_tuple); 
		/* and Update indexes (implicit) */

		if (Gp_role == GP_ROLE_DISPATCH)
		{
			stmtOptIdList = lappend_oid(stmtOptIdList, s1);
		}
	}

	if (HeapTupleIsValid(old_tuple))
		heap_freetuple(new_tuple);

	return stmtOptIdList;
} /* end AddUpdResqueueCapabilityEntryInternal */
Beispiel #6
0
/*
 * InsertRule -
 *	  takes the arguments and inserts them as a row into the system
 *	  relation "pg_rewrite"
 */
static Oid
InsertRule(char *rulname,
		   int evtype,
		   Oid eventrel_oid,
		   AttrNumber evslot_index,
		   bool evinstead,
		   Node *event_qual,
		   List *action,
		   bool replace,
		   Oid ruleOid)
{
	char	   *evqual = nodeToString(event_qual);
	char	   *actiontree = nodeToString((Node *) action);
	int			i;
	Datum		values[Natts_pg_rewrite];
	bool		nulls[Natts_pg_rewrite];
	bool		replaces[Natts_pg_rewrite];
	NameData	rname;
	HeapTuple	tup,
				oldtup;
	Oid			rewriteObjectId;
	ObjectAddress myself,
				referenced;
	bool		is_update = false;
	cqContext  *pcqCtx;

	/*
	 * Set up *nulls and *values arrays
	 */
	MemSet(nulls, false, sizeof(nulls));

	i = 0;
	namestrcpy(&rname, rulname);
	values[i++] = NameGetDatum(&rname); /* rulename */
	values[i++] = ObjectIdGetDatum(eventrel_oid);		/* ev_class */
	values[i++] = Int16GetDatum(evslot_index);	/* ev_attr */
	values[i++] = CharGetDatum(evtype + '0');	/* ev_type */
	values[i++] = BoolGetDatum(evinstead);		/* is_instead */
	values[i++] = CStringGetTextDatum(evqual);	/* ev_qual */
	values[i++] = CStringGetTextDatum(actiontree);		/* ev_action */

	/*
	 * Ready to store new pg_rewrite tuple
	 */

	/*
	 * Check to see if we are replacing an existing tuple
	 */
	pcqCtx = caql_beginscan(
			NULL,
			cql("SELECT * FROM pg_rewrite "
				" WHERE ev_class = :1 "
				" AND rulename = :2 "
				" FOR UPDATE ",
				ObjectIdGetDatum(eventrel_oid),
				CStringGetDatum(rulname)));
	
	oldtup = caql_getnext(pcqCtx);

	if (HeapTupleIsValid(oldtup))
	{
		if (!replace)
			ereport(ERROR,
					(errcode(ERRCODE_DUPLICATE_OBJECT),
					 errmsg("rule \"%s\" for relation \"%s\" already exists",
							rulname, get_rel_name(eventrel_oid))));

		/*
		 * When replacing, we don't need to replace every attribute
		 */
		MemSet(replaces, false, sizeof(replaces));
		replaces[Anum_pg_rewrite_ev_attr - 1] = true;
		replaces[Anum_pg_rewrite_ev_type - 1] = true;
		replaces[Anum_pg_rewrite_is_instead - 1] = true;
		replaces[Anum_pg_rewrite_ev_qual - 1] = true;
		replaces[Anum_pg_rewrite_ev_action - 1] = true;

		tup = caql_modify_current(pcqCtx,
								  values, nulls, replaces);

		caql_update_current(pcqCtx, tup);
		/* and Update indexes (implicit) */

		rewriteObjectId = HeapTupleGetOid(tup);
		is_update = true;
	}
	else
	{
		tup = caql_form_tuple(pcqCtx, values, nulls);

		if (OidIsValid(ruleOid))
			HeapTupleSetOid(tup, ruleOid);

		rewriteObjectId = caql_insert(pcqCtx, tup);
		/* and Update indexes (implicit) */
	}

	heap_freetuple(tup);

	/* If replacing, get rid of old dependencies and make new ones */
	if (is_update)
		deleteDependencyRecordsFor(RewriteRelationId, rewriteObjectId);

	/*
	 * Install dependency on rule's relation to ensure it will go away on
	 * relation deletion.  If the rule is ON SELECT, make the dependency
	 * implicit --- this prevents deleting a view's SELECT rule.  Other kinds
	 * of rules can be AUTO.
	 */
	myself.classId = RewriteRelationId;
	myself.objectId = rewriteObjectId;
	myself.objectSubId = 0;

	referenced.classId = RelationRelationId;
	referenced.objectId = eventrel_oid;
	referenced.objectSubId = 0;

	recordDependencyOn(&myself, &referenced,
			 (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);

	/*
	 * Also install dependencies on objects referenced in action and qual.
	 */
	recordDependencyOnExpr(&myself, (Node *) action, NIL,
						   DEPENDENCY_NORMAL);

	if (event_qual != NULL)
	{
		/* Find query containing OLD/NEW rtable entries */
		Query	   *qry = (Query *) linitial(action);

		qry = getInsertSelectQuery(qry, NULL);
		recordDependencyOnExpr(&myself, event_qual, qry->rtable,
							   DEPENDENCY_NORMAL);
	}

	caql_endscan(pcqCtx);

	return rewriteObjectId;
}
Beispiel #7
0
/*
 * 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);
}
Beispiel #8
0
/*
 * 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);
}
Beispiel #9
0
/*
 * 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 */
Beispiel #10
0
/*
 * Change tablespace owner
 */
void
AlterTableSpaceOwner(const char *name, Oid newOwnerId)
{
	Relation	rel;
	Oid			tablespaceoid;
	cqContext	cqc;
	cqContext  *pcqCtx;
	Form_pg_tablespace spcForm;
	HeapTuple	tup;

	/* Search pg_tablespace */
	rel = heap_open(TableSpaceRelationId, RowExclusiveLock);

	pcqCtx = caql_addrel(cqclr(&cqc), rel);

	tup = caql_getfirst(
			pcqCtx,
			cql("SELECT * FROM pg_tablespace "
				" WHERE spcname = :1 "
				" FOR UPDATE ",
				CStringGetDatum(name)));

	if (!HeapTupleIsValid(tup))
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("tablespace \"%s\" does not exist", name)));

	tablespaceoid = HeapTupleGetOid(tup);
	spcForm = (Form_pg_tablespace) 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 (spcForm->spcowner != newOwnerId)
	{
		Datum		repl_val[Natts_pg_tablespace];
		bool		repl_null[Natts_pg_tablespace];
		bool		repl_repl[Natts_pg_tablespace];
		Acl		   *newAcl;
		Datum		aclDatum;
		bool		isNull;
		HeapTuple	newtuple;

		/* Otherwise, must be owner of the existing object */
		if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId()))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
						   name);

		/* Must be able to become new owner */
		check_is_member_of_role(GetUserId(), newOwnerId);

		/*
		 * Normally we would also check for create permissions here, but there
		 * are none for tablespaces so we follow what rename tablespace does
		 * and omit the create permissions check.
		 *
		 * NOTE: Only superusers may create tablespaces to begin with and so
		 * initially only a superuser would be able to change its ownership
		 * anyway.
		 */

		memset(repl_null, false, sizeof(repl_null));
		memset(repl_repl, false, sizeof(repl_repl));

		repl_repl[Anum_pg_tablespace_spcowner - 1] = true;
		repl_val[Anum_pg_tablespace_spcowner - 1] = ObjectIdGetDatum(newOwnerId);

		/*
		 * Determine the modified ACL for the new owner.  This is only
		 * necessary when the ACL is non-null.
		 */
		aclDatum = heap_getattr(tup,
								Anum_pg_tablespace_spcacl,
								RelationGetDescr(rel),
								&isNull);
		if (!isNull)
		{
			newAcl = aclnewowner(DatumGetAclP(aclDatum),
								 spcForm->spcowner, newOwnerId);
			repl_repl[Anum_pg_tablespace_spcacl - 1] = true;
			repl_val[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(newAcl);
		}

		newtuple = caql_modify_current(pcqCtx, repl_val, repl_null, repl_repl);

		caql_update_current(pcqCtx, newtuple);
		/* and Update indexes (implicit) */

		/* MPP-6929: metadata tracking */
		if (Gp_role == GP_ROLE_DISPATCH)
			MetaTrackUpdObject(TableSpaceRelationId,
							   tablespaceoid,
							   GetUserId(),
							   "ALTER", "OWNER"
					);

		heap_freetuple(newtuple);

		/* Update owner dependency reference */
		changeDependencyOnOwner(TableSpaceRelationId, HeapTupleGetOid(tup),
								newOwnerId);
	}

	heap_close(rel, NoLock);
}
Beispiel #11
0
/*
 * Rename a tablespace
 */
void
RenameTableSpace(const char *oldname, const char *newname)
{
	Relation	rel;
	Oid			tablespaceoid;
	cqContext	cqc;
	cqContext	cqc2;
	cqContext  *pcqCtx;
	HeapTuple	newtuple;
	Form_pg_tablespace newform;

	/* Search pg_tablespace */
	rel = heap_open(TableSpaceRelationId, RowExclusiveLock);

	pcqCtx = caql_addrel(cqclr(&cqc), rel);

	newtuple = caql_getfirst(
			pcqCtx,
			cql("SELECT * FROM pg_tablespace "
				" WHERE spcname = :1 "
				" FOR UPDATE ",
				CStringGetDatum(oldname)));

	if (!HeapTupleIsValid(newtuple))
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("tablespace \"%s\" does not exist",
						oldname)));

	newform = (Form_pg_tablespace) GETSTRUCT(newtuple);

	/* Must be owner */
	tablespaceoid = HeapTupleGetOid(newtuple);
	if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId()))
		aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname);

	/* Validate new name */
	if (!allowSystemTableModsDDL && IsReservedName(newname))
	{
		ereport(ERROR,
				(errcode(ERRCODE_RESERVED_NAME),
				 errmsg("unacceptable tablespace name \"%s\"", newname),
				 errdetail("The prefix \"%s\" is reserved for system tablespaces.",
						   GetReservedPrefix(newname))));
	}

	/* Make sure the new name doesn't exist */
	if (caql_getcount(
				caql_addrel(cqclr(&cqc2), rel), /* rely on rowexclusive */
				cql("SELECT COUNT(*) FROM pg_tablespace "
					" WHERE spcname = :1 ",
					CStringGetDatum(newname))))
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("tablespace \"%s\" already exists",
						newname)));

	/* OK, update the entry */
	namestrcpy(&(newform->spcname), newname);

	caql_update_current(pcqCtx, newtuple);
	/* and Update indexes (implicit) */

	/* MPP-6929: metadata tracking */
	if (Gp_role == GP_ROLE_DISPATCH)
		MetaTrackUpdObject(TableSpaceRelationId,
						   tablespaceoid,
						   GetUserId(),
						   "ALTER", "RENAME"
				);

	heap_close(rel, NoLock);
}
Beispiel #12
0
/*
 * shdepChangeDep
 *
 * Update shared dependency records to account for an updated referenced
 * object.	This is an internal workhorse for operations such as changing
 * an object's owner.
 *
 * There must be no more than one existing entry for the given dependent
 * object and dependency type!	So in practice this can only be used for
 * updating SHARED_DEPENDENCY_OWNER entries, which should have that property.
 *
 * If there is no previous entry, we assume it was referencing a PINned
 * object, so we create a new entry.  If the new referenced object is
 * PINned, we don't create an entry (and drop the old one, if any).
 *
 * sdepRel must be the pg_shdepend relation, already opened and suitably
 * locked.
 */
static void
shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
			   Oid refclassid, Oid refobjid,
			   SharedDependencyType deptype)
{
	Oid			dbid = classIdGetDbId(classid);
	bool		bGotOne = false;
	HeapTuple	oldtup = NULL;
	HeapTuple	scantup;
	cqContext  *pcqCtx;
	cqContext	cqc;

	/*
	 * Make sure the new referenced object doesn't go away while we record the
	 * dependency.
	 */
	shdepLockAndCheckObject(refclassid, refobjid);

	/*
	 * Look for a previous entry
	 */
	
	pcqCtx = caql_beginscan(
			caql_addrel(cqclr(&cqc), sdepRel),
			cql("SELECT * FROM pg_shdepend "
				" WHERE dbid = :1 "
				" AND classid = :2 "
				" AND objid = :3 "
				" FOR UPDATE ",
				ObjectIdGetDatum(dbid),
				ObjectIdGetDatum(classid),
				ObjectIdGetDatum(objid)));

	while (HeapTupleIsValid(scantup = caql_getnext(pcqCtx)))
	{
		/* Ignore if not of the target dependency type */
		if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype)
			continue;
		/* Caller screwed up if multiple matches */
		if (bGotOne)
			elog(ERROR,
				 "multiple pg_shdepend entries for object %u/%u deptype %c",
				 classid, objid, deptype);
		bGotOne = true;
	}
	caql_endscan(pcqCtx);

	/* XXX XXX XXX XXX XXX XXX XXX XXX XXX
	 * Should match this logic:
	 *
	 *  if isSharedObjectpinned
	 *     if Gotone then drop it
	 *  else 
     *     if Gotone 
     *     then update it
     *     else insert it
	 *
	 * XXX XXX XXX XXX XXX XXX XXX XXX XXX
	 */ 

	if (!bGotOne) /* no match */
	{
		/* if no match and pinned, new entry not needed */
		if (isSharedObjectPinned(refclassid, refobjid, sdepRel))
		{
			/* just return -- don't need to free anything because
			 * sdelRel was passed in, and pcqCtx is freed 
			 */
			return;
		}

		pcqCtx = caql_beginscan(
				caql_addrel(cqclr(&cqc), sdepRel),
				cql("INSERT INTO pg_shdepend ",
					NULL));

		/* Need to insert new entry */
		Datum		values[Natts_pg_shdepend];
		bool		nulls[Natts_pg_shdepend];

		memset(nulls, 0, sizeof(nulls));

		values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid);
		values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid);
		values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid);

		values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid);
		values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid);
		values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);

		/*
		 * we are reusing oldtup just to avoid declaring a new variable, but
		 * it's certainly a new tuple
		 */
		oldtup = caql_form_tuple(pcqCtx, values, nulls);
		caql_insert(pcqCtx, oldtup);
		/* and Update indexes (implicit) */

		heap_freetuple(oldtup);
		caql_endscan(pcqCtx);
	}
	else
	{
		/* XXX XXX Do the scan again, but do the update/delete this time */

		pcqCtx = caql_beginscan(
				caql_addrel(cqclr(&cqc), sdepRel),
				cql("SELECT * FROM pg_shdepend "
					" WHERE dbid = :1 "
					" AND classid = :2 "
					" AND objid = :3 "
					" FOR UPDATE ",
					ObjectIdGetDatum(dbid),
					ObjectIdGetDatum(classid),
					ObjectIdGetDatum(objid)));

		while (HeapTupleIsValid(scantup = caql_getnext(pcqCtx)))
		{
			/* Ignore if not of the target dependency type */
			if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype)
				continue;
			/* 
			 * NOTE: already tested for multiple matches - just use
			 * first one 
			 */

			if (isSharedObjectPinned(refclassid, refobjid, sdepRel))
			{
				/* No new entry needed, so just delete existing entry if any */
				caql_delete_current(pcqCtx);
			}
			else
			{
				oldtup = heap_copytuple(scantup);

				/* Need to update existing entry */
				Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup);

				/* Since oldtup is a copy, we can just modify it in-memory */
				shForm->refclassid = refclassid;
				shForm->refobjid = refobjid;

				caql_update_current(pcqCtx, oldtup);
				/* and Update indexes (implicit) */

				heap_freetuple(oldtup);
			}
			break;
		}
		caql_endscan(pcqCtx);
	}

}
Beispiel #13
0
/*
 * OperatorUpd
 *
 *	For a given operator, look up its negator and commutator operators.
 *	If they are defined, but their negator and commutator fields
 *	(respectively) are empty, then use the new operator for neg or comm.
 *	This solves a problem for users who need to insert two new operators
 *	which are the negator or commutator of each other.
 */
static void
OperatorUpd(Oid baseId, Oid commId, Oid negId)
{
	int			i;
	Relation	pg_operator_desc;
	HeapTuple	tup;
	bool		nulls[Natts_pg_operator];
	bool		replaces[Natts_pg_operator];
	Datum		values[Natts_pg_operator];
	cqContext	cqc;
	cqContext  *pcqCtx;

	for (i = 0; i < Natts_pg_operator; ++i)
	{
		values[i] = (Datum) 0;
		replaces[i] = false;
		nulls[i] = false;
	}

	/*
	 * check and update the commutator & negator, if necessary
	 *
	 * We need a CommandCounterIncrement here in case of a self-commutator
	 * operator: we'll need to update the tuple that we just inserted.
	 */
	CommandCounterIncrement();

	pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);

	pcqCtx = caql_addrel(cqclr(&cqc), pg_operator_desc);

	tup = caql_getfirst(
			pcqCtx,
			cql("SELECT * FROM pg_operator "
				" WHERE oid = :1 "
				" FOR UPDATE ",
				ObjectIdGetDatum(commId)));

	/*
	 * if the commutator and negator are the same operator, do one update. XXX
	 * this is probably useless code --- I doubt it ever makes sense for
	 * commutator and negator to be the same thing...
	 */
	if (commId == negId)
	{
		if (HeapTupleIsValid(tup))
		{
			Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);

			if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
			{
				if (!OidIsValid(t->oprnegate))
				{
					values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
					replaces[Anum_pg_operator_oprnegate - 1] = true;
				}

				if (!OidIsValid(t->oprcom))
				{
					values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
					replaces[Anum_pg_operator_oprcom - 1] = true;
				}

				tup = caql_modify_current(pcqCtx,
										  values,
										  nulls,
										  replaces);

				caql_update_current(pcqCtx, tup);
				/* and Update indexes (implicit) */
			}
		}

		heap_close(pg_operator_desc, RowExclusiveLock);

		return;
	}

	/* if commutator and negator are different, do two updates */

	if (HeapTupleIsValid(tup) &&
		!(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
	{
		values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
		replaces[Anum_pg_operator_oprcom - 1] = true;

		tup = caql_modify_current(pcqCtx,
								  values,
								  nulls,
								  replaces);

		caql_update_current(pcqCtx, tup);
		/* and Update indexes (implicit) */

		/* XXX XXX XXX XXX XXX XXX
		 * NOTE: reset the values/replaces arrays *after*
		 * this update because we might re-use them in the next update
		 * XXX XXX XXX XXX XXX XXX
		 */
		values[Anum_pg_operator_oprcom - 1] = (Datum) 0;
		replaces[Anum_pg_operator_oprcom - 1] = false;
	}

	/* check and update the negator, if necessary */

	/* reset the context and re-use it */
	pcqCtx = caql_addrel(cqclr(&cqc), pg_operator_desc); 

	tup = caql_getfirst(
			pcqCtx,
			cql("SELECT * FROM pg_operator "
				" WHERE oid = :1 "
				" FOR UPDATE ",
				ObjectIdGetDatum(negId)));

	if (HeapTupleIsValid(tup) &&
		!(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
	{
		values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
		replaces[Anum_pg_operator_oprnegate - 1] = true;

		tup = caql_modify_current(pcqCtx,
								values,
								nulls,
								replaces);

		caql_update_current(pcqCtx, tup);
		/* and Update indexes (implicit) */
	}

	heap_close(pg_operator_desc, RowExclusiveLock);
}
Beispiel #14
0
Oid
OperatorCreateWithOid(const char *operatorName,
			   Oid operatorNamespace,
			   Oid leftTypeId,
			   Oid rightTypeId,
			   List *procedureName,
			   List *commutatorName,
			   List *negatorName,
			   List *restrictionName,
			   List *joinName,
			   bool canMerge,
			   bool canHash,
			   Oid newOid)
{
	Relation	pg_operator_desc;
	HeapTuple	tup;
	bool		nulls[Natts_pg_operator];
	bool		replaces[Natts_pg_operator];
	Datum		values[Natts_pg_operator];
	Oid			operatorObjectId;
	bool		operatorAlreadyDefined;
	Oid			procOid;
	Oid			operResultType;
	Oid			commutatorId,
				negatorId,
				restOid,
				joinOid;
	bool		selfCommutator = false;
	Oid			typeId[4];		/* only need up to 4 args here */
	int			nargs;
	NameData	oname;
	int			i;
	cqContext	cqc;
	cqContext  *pcqCtx;

	/*
	 * Sanity checks
	 */
	if (!validOperatorName(operatorName))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_NAME),
				 errmsg("\"%s\" is not a valid operator name",
						operatorName)));

	if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
		   errmsg("at least one of leftarg or rightarg must be specified")));

	if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
	{
		/* If it's not a binary op, these things mustn't be set: */
		if (commutatorName)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 errmsg("only binary operators can have commutators")));
		if (joinName)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("only binary operators can have join selectivity")));
		if (canMerge)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 errmsg("only binary operators can merge join")));
		if (canHash)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 errmsg("only binary operators can hash")));
	}

	operatorObjectId = OperatorGet(operatorName,
								   operatorNamespace,
								   leftTypeId,
								   rightTypeId,
								   &operatorAlreadyDefined);

	if (operatorAlreadyDefined)
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_FUNCTION),
				 errmsg("operator %s already exists",
						operatorName)));

	/*
	 * At this point, if operatorObjectId is not InvalidOid then we are
	 * filling in a previously-created shell.
	 */

	/*
	 * Look up registered procedures -- find the return type of procedureName
	 * to place in "result" field. Do this before shells are created so we
	 * don't have to worry about deleting them later.
	 */
	if (!OidIsValid(leftTypeId))
	{
		typeId[0] = rightTypeId;
		nargs = 1;
	}
	else if (!OidIsValid(rightTypeId))
	{
		typeId[0] = leftTypeId;
		nargs = 1;
	}
	else
	{
		typeId[0] = leftTypeId;
		typeId[1] = rightTypeId;
		nargs = 2;
	}
	procOid = LookupFuncName(procedureName, nargs, typeId, false);
	operResultType = get_func_rettype(procOid);

	/*
	 * find restriction estimator
	 */
	if (restrictionName)
	{
		typeId[0] = INTERNALOID;	/* Query */
		typeId[1] = OIDOID;		/* operator OID */
		typeId[2] = INTERNALOID;	/* args list */
		typeId[3] = INT4OID;	/* varRelid */

		restOid = LookupFuncName(restrictionName, 4, typeId, false);
	}
	else
		restOid = InvalidOid;

	/*
	 * find join estimator
	 */
	if (joinName)
	{
		typeId[0] = INTERNALOID;	/* Query */
		typeId[1] = OIDOID;		/* operator OID */
		typeId[2] = INTERNALOID;	/* args list */
		typeId[3] = INT2OID;	/* jointype */

		joinOid = LookupFuncName(joinName, 4, typeId, false);
	}
	else
		joinOid = InvalidOid;

	/*
	 * set up values in the operator tuple
	 */

	for (i = 0; i < Natts_pg_operator; ++i)
	{
		values[i] = 0;
		replaces[i] = true;
		nulls[i] = false;
	}

	i = 0;
	namestrcpy(&oname, operatorName);
	values[i++] = NameGetDatum(&oname); /* oprname */
	values[i++] = ObjectIdGetDatum(operatorNamespace);	/* oprnamespace */
	values[i++] = ObjectIdGetDatum(GetUserId());		/* oprowner */
	values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');	/* oprkind */
	values[i++] = BoolGetDatum(canMerge);		/* oprcanmerge */
	values[i++] = BoolGetDatum(canHash);		/* oprcanhash */
	values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
	values[i++] = ObjectIdGetDatum(rightTypeId);		/* oprright */
	values[i++] = ObjectIdGetDatum(operResultType);		/* oprresult */

	/*
	 * Set up the other operators.	If they do not currently exist, create
	 * shells in order to get ObjectId's.
	 */

	if (commutatorName)
	{
		/* commutator has reversed arg types */
		commutatorId = get_other_operator(commutatorName,
										  rightTypeId, leftTypeId,
										  operatorName, operatorNamespace,
										  leftTypeId, rightTypeId,
										  true);

		/*
		 * self-linkage to this operator; will fix below. Note that only
		 * self-linkage for commutation makes sense.
		 */
		if (!OidIsValid(commutatorId))
			selfCommutator = true;
	}
	else
		commutatorId = InvalidOid;
	values[i++] = ObjectIdGetDatum(commutatorId);		/* oprcom */

	if (negatorName)
	{
		/* negator has same arg types */
		negatorId = get_other_operator(negatorName,
									   leftTypeId, rightTypeId,
									   operatorName, operatorNamespace,
									   leftTypeId, rightTypeId,
									   false);
	}
	else
		negatorId = InvalidOid;
	values[i++] = ObjectIdGetDatum(negatorId);	/* oprnegate */

	values[i++] = ObjectIdGetDatum(procOid);	/* oprcode */
	values[i++] = ObjectIdGetDatum(restOid);	/* oprrest */
	values[i++] = ObjectIdGetDatum(joinOid);	/* oprjoin */

	pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);

	pcqCtx = caql_addrel(cqclr(&cqc), pg_operator_desc);

	/*
	 * If we are replacing an operator shell, update; else insert
	 */
	if (operatorObjectId)
	{
		tup = caql_getfirst(
					pcqCtx,
					cql("SELECT * FROM pg_operator "
						" WHERE oid = :1 "
						" FOR UPDATE ",
						ObjectIdGetDatum(operatorObjectId)));

		if (!HeapTupleIsValid(tup))
			elog(ERROR, "cache lookup failed for operator %u",
				 operatorObjectId);

		tup = caql_modify_current(pcqCtx,
								  values,
								  nulls,
								  replaces);
		
		caql_update_current(pcqCtx, tup);
		/* and Update indexes (implicit) */
	}
	else
	{
		tup = caql_form_tuple(pcqCtx, values, nulls);
		
		if (newOid != (Oid) 0)
			HeapTupleSetOid(tup, newOid);

		operatorObjectId = caql_insert(pcqCtx, tup);
		/* and Update indexes (implicit) */
	}

	/* Add dependencies for the entry */
	makeOperatorDependencies(tup);

	heap_close(pg_operator_desc, RowExclusiveLock);

	/*
	 * If a commutator and/or negator link is provided, update the other
	 * operator(s) to point at this one, if they don't already have a link.
	 * This supports an alternative style of operator definition wherein the
	 * user first defines one operator without giving negator or commutator,
	 * then defines the other operator of the pair with the proper commutator
	 * or negator attribute.  That style doesn't require creation of a shell,
	 * and it's the only style that worked right before Postgres version 6.5.
	 * This code also takes care of the situation where the new operator is
	 * its own commutator.
	 */
	if (selfCommutator)
		commutatorId = operatorObjectId;

	if (OidIsValid(commutatorId) || OidIsValid(negatorId))
		OperatorUpd(operatorObjectId, commutatorId, negatorId);
		
	return operatorObjectId;
}
Beispiel #15
0
/* ----------------------------------------------------------------
 *		TypeCreate
 *
 *		This does all the necessary work needed to define a new type.
 *
 *		Returns the OID assigned to the new type.
 * ----------------------------------------------------------------
 */
Oid
TypeCreateWithOid(const char *typeName,
		   Oid typeNamespace,
		   Oid relationOid,		/* only for 'c'atalog types */
		   char relationKind,	/* ditto */
		   Oid ownerId,
		   int16 internalSize,
		   char typeType,
		   char typDelim,
		   Oid inputProcedure,
		   Oid outputProcedure,
		   Oid receiveProcedure,
		   Oid sendProcedure,
		   Oid analyzeProcedure,
		   Oid elementType,
		   Oid baseType,
		   const char *defaultTypeValue,		/* human readable rep */
		   char *defaultTypeBin,	/* cooked rep */
		   bool passedByValue,
		   char alignment,
		   char storage,
		   int32 typeMod,
		   int32 typNDims,		/* Array dimensions for baseType */
		   bool typeNotNull,
		   Oid newtypeOid,
		   Datum typoptions)
{
	Relation	pg_type_desc;
	Oid			typeObjectId;
	bool		rebuildDeps = false;
	HeapTuple	tup;
	bool		nulls[Natts_pg_type];
	bool		replaces[Natts_pg_type];
	Datum		values[Natts_pg_type];
	NameData	name;
	int			i;
	cqContext	*pcqCtx;
	cqContext	 cqc;

	/*
	 * We assume that the caller validated the arguments individually, but did
	 * not check for bad combinations.
	 *
	 * Validate size specifications: either positive (fixed-length) or -1
	 * (varlena) or -2 (cstring).  Pass-by-value types must have a fixed
	 * length not more than sizeof(Datum).
	 */
	if (!(internalSize > 0 ||
		  internalSize == -1 ||
		  internalSize == -2))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("invalid type internal size %d",
						internalSize)));
	if (passedByValue &&
		(internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
			   errmsg("internal size %d is invalid for passed-by-value type",
					  internalSize)));

	/* Only varlena types can be toasted */
	if (storage != 'p' && internalSize != -1)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("fixed-size types must have storage PLAIN")));

	/*
	 * initialize arrays needed for heap_form_tuple or heap_modify_tuple
	 */
	for (i = 0; i < Natts_pg_type; ++i)
	{
		nulls[i] = false;
		replaces[i] = true;
		values[i] = (Datum) 0;
	}

	/*
	 * initialize the *values information
	 */
	i = 0;
	namestrcpy(&name, typeName);
	values[i++] = NameGetDatum(&name);	/* typname */
	values[i++] = ObjectIdGetDatum(typeNamespace);		/* typnamespace */
	values[i++] = ObjectIdGetDatum(ownerId);		/* typowner */
	values[i++] = Int16GetDatum(internalSize);	/* typlen */
	values[i++] = BoolGetDatum(passedByValue);	/* typbyval */
	values[i++] = CharGetDatum(typeType);		/* typtype */
	values[i++] = BoolGetDatum(true);	/* typisdefined */
	values[i++] = CharGetDatum(typDelim);		/* typdelim */
	values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* typrelid */
	values[i++] = ObjectIdGetDatum(elementType);		/* typelem */
	values[i++] = ObjectIdGetDatum(inputProcedure);		/* typinput */
	values[i++] = ObjectIdGetDatum(outputProcedure);	/* typoutput */
	values[i++] = ObjectIdGetDatum(receiveProcedure);	/* typreceive */
	values[i++] = ObjectIdGetDatum(sendProcedure);		/* typsend */
	values[i++] = ObjectIdGetDatum(analyzeProcedure);	/* typanalyze */
	values[i++] = CharGetDatum(alignment);		/* typalign */
	values[i++] = CharGetDatum(storage);		/* typstorage */
	values[i++] = BoolGetDatum(typeNotNull);	/* typnotnull */
	values[i++] = ObjectIdGetDatum(baseType);	/* typbasetype */
	values[i++] = Int32GetDatum(typeMod);		/* typtypmod */
	values[i++] = Int32GetDatum(typNDims);		/* typndims */

	/*
	 * initialize the default binary value for this type.  Check for nulls of
	 * course.
	 */
	if (defaultTypeBin)
		values[i] = CStringGetTextDatum(defaultTypeBin);
	else
		nulls[i] = true;
	i++;						/* typdefaultbin */

	/*
	 * initialize the default value for this type.
	 */
	if (defaultTypeValue)
		values[i] = CStringGetTextDatum(defaultTypeValue);
	else
		nulls[i] = true;
	i++;						/* typdefault */

	/*
	 * open pg_type and prepare to insert or update a row.
	 *
	 * NOTE: updating will not work correctly in bootstrap mode; but we don't
	 * expect to be overwriting any shell types in bootstrap mode.
	 */
	pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);

	pcqCtx = caql_addrel(cqclr(&cqc), pg_type_desc);

	tup = caql_getfirst(
			pcqCtx,
			cql("SELECT * FROM pg_type "
				" WHERE typname = :1 "
				" AND typnamespace = :2 "
				" FOR UPDATE ",
				CStringGetDatum((char *) typeName),
				ObjectIdGetDatum(typeNamespace)));

	if (HeapTupleIsValid(tup))
	{
		/*
		 * check that the type is not already defined.	It may exist as a
		 * shell type, however.
		 */
		if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
			ereport(ERROR,
					(errcode(ERRCODE_DUPLICATE_OBJECT),
					 errmsg("type \"%s\" already exists", typeName)));

		/*
		 * shell type must have been created by same owner
		 */
		if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId)
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);

		/*
		 * Okay to update existing shell type tuple
		 */
		tup = caql_modify_current(pcqCtx,
								  values,
								  nulls,
								  replaces);

		caql_update_current(pcqCtx, tup);
		/* and Update indexes (implicit) */

		typeObjectId = HeapTupleGetOid(tup);

		rebuildDeps = true;		/* get rid of shell type's dependencies */
	}
	else
	{
		tup = caql_form_tuple(pcqCtx, values, nulls);
						 
		if (newtypeOid != InvalidOid)
		{
			elog(DEBUG5," Setting Oid in new pg_type tuple");
			HeapTupleSetOid(tup, newtypeOid);
		}
		else if (Gp_role == GP_ROLE_EXECUTE) elog(ERROR," newtypeOid NULL");

		/* Insert tuple into the relation */
		typeObjectId = caql_insert(pcqCtx, tup);
		/* and Update indexes (implicit) */
	}

	/*
	 * Create dependencies.  We can/must skip this in bootstrap mode.
	 */
	if (!IsBootstrapProcessingMode())
		GenerateTypeDependencies(typeNamespace,
								 typeObjectId,
								 relationOid,
								 relationKind,
								 ownerId,
								 inputProcedure,
								 outputProcedure,
								 receiveProcedure,
								 sendProcedure,
								 analyzeProcedure,
								 elementType,
								 baseType,
								 (defaultTypeBin ?
								  stringToNode(defaultTypeBin) :
								  NULL),
								 rebuildDeps);

	/*
	 * finish up with pg_type
	 */
	heap_close(pg_type_desc, RowExclusiveLock);

	/* now pg_type_encoding */
	if (DatumGetPointer(typoptions) != NULL)
		add_type_encoding(typeObjectId, typoptions);

	return typeObjectId;
}