Ejemplo n.º 1
0
/*
 * Change language owner
 */
void
AlterLanguageOwner(const char *name, Oid newOwnerId)
{
	HeapTuple	tup;
	Relation	rel;

	/* Translate name for consistency with CREATE */
	name = case_translate_language_name(name);

	rel = heap_open(LanguageRelationId, RowExclusiveLock);

	tup = SearchSysCache(LANGNAME,
						 CStringGetDatum(name),
						 0, 0, 0);
	if (!HeapTupleIsValid(tup))
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("language \"%s\" does not exist", name)));

	AlterLanguageOwner_internal(tup, rel, newOwnerId);
	
	ReleaseSysCache(tup);
	
	heap_close(rel, RowExclusiveLock);

}
Ejemplo n.º 2
0
/* ---------------------------------------------------------------------
 * DROP PROCEDURAL LANGUAGE
 * ---------------------------------------------------------------------
 */
void
DropProceduralLanguage(DropPLangStmt *stmt)
{
	char	   *languageName;
	HeapTuple	langTup;
	ObjectAddress object;

	/*
	 * Translate the language name, check that the language exists
	 */
	languageName = case_translate_language_name(stmt->plname);

	langTup = SearchSysCache(LANGNAME,
							 CStringGetDatum(languageName),
							 0, 0, 0);
	if (!HeapTupleIsValid(langTup))
	{
		if (!stmt->missing_ok)
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_OBJECT),
					 errmsg("language \"%s\" does not exist", languageName)));
		else
			ereport(NOTICE,
					(errmsg("language \"%s\" does not exist, skipping",
							languageName)));

		return;
	}

	/*
	 * Check permission
	 */
	if (!pg_language_ownercheck(HeapTupleGetOid(langTup), GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
					   languageName);

	object.classId = LanguageRelationId;
	object.objectId = HeapTupleGetOid(langTup);
	object.objectSubId = 0;

	ReleaseSysCache(langTup);

	/*
	 * Do the deletion
	 */
	performDeletion(&object, stmt->behavior);

	if (Gp_role == GP_ROLE_DISPATCH)
	{
		CdbDispatchUtilityStatement((Node *) stmt,
									DF_CANCEL_ON_ERROR|
									DF_WITH_SNAPSHOT|
									DF_NEED_TWO_PHASE,
									NIL,
									NULL);
	}
}
Ejemplo n.º 3
0
/*
 * Rename language
 */
void
RenameLanguage(const char *oldname, const char *newname)
{
	HeapTuple	tup;
	Relation	rel;

	/* Translate both names for consistency with CREATE */
	oldname = case_translate_language_name(oldname);
	newname = case_translate_language_name(newname);

	rel = heap_open(LanguageRelationId, RowExclusiveLock);

	tup = SearchSysCacheCopy(LANGNAME,
							 CStringGetDatum(oldname),
							 0, 0, 0);
	if (!HeapTupleIsValid(tup))
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("language \"%s\" does not exist", oldname)));

	/* make sure the new name doesn't exist */
	if (SearchSysCacheExists(LANGNAME,
							 CStringGetDatum(newname),
							 0, 0, 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("language \"%s\" already exists", newname)));
	}

	/* must be owner of PL */
	if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
					   oldname);

	/* rename */
	namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
	simple_heap_update(rel, &tup->t_self, tup);
	CatalogUpdateIndexes(rel, tup);

	heap_close(rel, NoLock);
	heap_freetuple(tup);
}
Ejemplo n.º 4
0
/*
 * Rename language
 */
void
RenameLanguage(const char *oldname, const char *newname)
{
	HeapTuple	tup;
	Relation	rel;

	/* Translate both names for consistency with CREATE */
	oldname = case_translate_language_name(oldname);
	newname = case_translate_language_name(newname);

	rel = heap_open(LanguageRelationId, RowExclusiveLock);

	tup = SearchSysCacheCopy(LANGNAME,
							 CStringGetDatum(oldname),
							 0, 0, 0);
	if (!HeapTupleIsValid(tup))
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("language \"%s\" does not exist", oldname)));

	/* make sure the new name doesn't exist */
	if (SearchSysCacheExists(LANGNAME,
							 CStringGetDatum(newname),
							 0, 0, 0))
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("language \"%s\" already exists", newname)));

	/* must be superuser, since we do not have owners for PLs */
	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("must be superuser to rename procedural language")));

	/* rename */
	namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
	simple_heap_update(rel, &tup->t_self, tup);
	CatalogUpdateIndexes(rel, tup);

	heap_close(rel, NoLock);
	heap_freetuple(tup);
}
Ejemplo n.º 5
0
/* ---------------------------------------------------------------------
 * DROP PROCEDURAL LANGUAGE
 * ---------------------------------------------------------------------
 */
void
DropProceduralLanguage(DropPLangStmt *stmt)
{
	char	   *languageName;
	HeapTuple	langTup;
	ObjectAddress object;

	/*
	 * Check permission
	 */
	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("must be superuser to drop procedural language")));

	/*
	 * Translate the language name, check that the language exists
	 */
	languageName = case_translate_language_name(stmt->plname);

	langTup = SearchSysCache(LANGNAME,
							 CStringGetDatum(languageName),
							 0, 0, 0);
	if (!HeapTupleIsValid(langTup))
	{
		if (!stmt->missing_ok)
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_OBJECT),
					 errmsg("language \"%s\" does not exist", languageName)));
		else
			ereport(NOTICE,
					(errmsg("language \"%s\" does not exist, skipping",
							languageName)));

		return;
	}

	object.classId = LanguageRelationId;
	object.objectId = HeapTupleGetOid(langTup);
	object.objectSubId = 0;

	ReleaseSysCache(langTup);

	/*
	 * Do the deletion
	 */
	performDeletion(&object, stmt->behavior);
}
Ejemplo n.º 6
0
/* ---------------------------------------------------------------------
 * DROP PROCEDURAL LANGUAGE
 * ---------------------------------------------------------------------
 */
void
DropProceduralLanguage(DropPLangStmt *stmt)
{
	char	   *languageName;
	Oid			oid;
	ObjectAddress object;

	/*
	 * Translate the language name, check that the language exists
	 */
	languageName = case_translate_language_name(stmt->plname);

	oid = get_language_oid(languageName, stmt->missing_ok);
	if (!OidIsValid(oid))
	{
		ereport(NOTICE,
				(errmsg("language \"%s\" does not exist, skipping",
						languageName)));
		return;
	}

	/*
	 * Check permission
	 */
	if (!pg_language_ownercheck(oid, GetUserId()))
		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
					   languageName);

	object.classId = LanguageRelationId;
	object.objectId = oid;
	object.objectSubId = 0;

	/*
	 * Do the deletion
	 */
	performDeletion(&object, stmt->behavior);
}
Ejemplo n.º 7
0
/* ---------------------------------------------------------------------
 * CREATE PROCEDURAL LANGUAGE
 * ---------------------------------------------------------------------
 */
void
CreateProceduralLanguage(CreatePLangStmt *stmt)
{
	char	   *languageName;
	PLTemplate *pltemplate;
	Oid			handlerOid,
				valOid;
	Oid			funcrettype;
	Oid			funcargtypes[1];

	/*
	 * Check permission
	 */
	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("must be superuser to create procedural language")));

	/*
	 * Translate the language name and check that this language doesn't
	 * already exist
	 */
	languageName = case_translate_language_name(stmt->plname);

	if (SearchSysCacheExists(LANGNAME,
							 PointerGetDatum(languageName),
							 0, 0, 0))
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("language \"%s\" already exists", languageName)));

	/*
	 * If we have template information for the language, ignore the supplied
	 * parameters (if any) and use the template information.
	 */
	if ((pltemplate = find_language_template(languageName)) != NULL)
	{
		List	   *funcname;

		/*
		 * Give a notice if we are ignoring supplied parameters.
		 */
		if (stmt->plhandler)
			ereport(NOTICE,
					(errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));

		/*
		 * Find or create the handler function, which we force to be in the
		 * pg_catalog schema.  If already present, it must have the correct
		 * return type.
		 */
		funcname = SystemFuncName(pltemplate->tmplhandler);
		handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
		if (OidIsValid(handlerOid))
		{
			funcrettype = get_func_rettype(handlerOid);
			if (funcrettype != LANGUAGE_HANDLEROID)
				ereport(ERROR,
						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
				  errmsg("function %s must return type \"language_handler\"",
						 NameListToString(funcname))));
		}
		else
		{
			handlerOid = ProcedureCreate(pltemplate->tmplhandler,
										 PG_CATALOG_NAMESPACE,
										 false, /* replace */
										 false, /* returnsSet */
										 LANGUAGE_HANDLEROID,
										 ClanguageId,
										 F_FMGR_C_VALIDATOR,
										 pltemplate->tmplhandler,
										 pltemplate->tmpllibrary,
										 false, /* isAgg */
										 false, /* security_definer */
										 false, /* isStrict */
										 PROVOLATILE_VOLATILE,
										 buildoidvector(funcargtypes, 0),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL));
		}

		/*
		 * Likewise for the validator, if required; but we don't care about
		 * its return type.
		 */
		if (pltemplate->tmplvalidator)
		{
			funcname = SystemFuncName(pltemplate->tmplvalidator);
			funcargtypes[0] = OIDOID;
			valOid = LookupFuncName(funcname, 1, funcargtypes, true);
			if (!OidIsValid(valOid))
			{
				valOid = ProcedureCreate(pltemplate->tmplvalidator,
										 PG_CATALOG_NAMESPACE,
										 false, /* replace */
										 false, /* returnsSet */
										 VOIDOID,
										 ClanguageId,
										 F_FMGR_C_VALIDATOR,
										 pltemplate->tmplvalidator,
										 pltemplate->tmpllibrary,
										 false, /* isAgg */
										 false, /* security_definer */
										 false, /* isStrict */
										 PROVOLATILE_VOLATILE,
										 buildoidvector(funcargtypes, 1),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL));
			}
		}
		else
			valOid = InvalidOid;

		/* ok, create it */
		create_proc_lang(languageName, handlerOid, valOid,
						 pltemplate->tmpltrusted);
	}
	else
	{
		/*
		 * No template, so use the provided information.  If there's no
		 * handler clause, the user is trying to rely on a template that we
		 * don't have, so complain accordingly.
		 */
		if (!stmt->plhandler)
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_OBJECT),
					 errmsg("unsupported language \"%s\"",
							languageName),
					 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));

		/*
		 * Lookup the PL handler function and check that it is of the expected
		 * return type
		 */
		handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
		funcrettype = get_func_rettype(handlerOid);
		if (funcrettype != LANGUAGE_HANDLEROID)
		{
			/*
			 * We allow OPAQUE just so we can load old dump files.	When we
			 * see a handler function declared OPAQUE, change it to
			 * LANGUAGE_HANDLER.  (This is probably obsolete and removable?)
			 */
			if (funcrettype == OPAQUEOID)
			{
				ereport(WARNING,
						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
						 errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
								NameListToString(stmt->plhandler))));
				SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
			}
			else
				ereport(ERROR,
						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
				  errmsg("function %s must return type \"language_handler\"",
						 NameListToString(stmt->plhandler))));
		}

		/* validate the validator function */
		if (stmt->plvalidator)
		{
			funcargtypes[0] = OIDOID;
			valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
			/* return value is ignored, so we don't check the type */
		}
		else
			valOid = InvalidOid;

		/* ok, create it */
		create_proc_lang(languageName, handlerOid, valOid, stmt->pltrusted);
	}
}
Ejemplo n.º 8
0
/* ---------------------------------------------------------------------
 * CREATE PROCEDURAL LANGUAGE
 * ---------------------------------------------------------------------
 */
void
CreateProceduralLanguage(CreatePLangStmt *stmt)
{
	char	   *languageName;
	PLTemplate *pltemplate;
	Oid			handlerOid,
				inlineOid,
				valOid;
	Oid			funcrettype;
	Oid			funcargtypes[1];

	/*
	 * Translate the language name and check that this language doesn't
	 * already exist
	 */
	languageName = case_translate_language_name(stmt->plname);

	if (SearchSysCacheExists(LANGNAME,
							 PointerGetDatum(languageName),
							 0, 0, 0))
	{
		/*
		 * MPP-7563: special case plpgsql to omit a notice if it already exists
		 * rather than an error.  This allows us to install plpgsql by default
		 * while allowing it to be dropped and not create issues for 
		 * dump/restore.  This should be phased out in a later releases if/when
		 * plpgsql becomes a true internal language that can not be dropped.
		 *
		 * Note: hardcoding this on the name is semi-safe since we would ignore 
		 * any handler functions anyways since plpgsql exists in pg_pltemplate.
		 * Alternatively this logic could be extended to apply to all languages
		 * in pg_pltemplate.
		 */
		if (strcmp(languageName, "plpgsql") == 0) 
		{
			ereport(NOTICE,
					(errmsg("language \"plpgsql\" already exists, skipping")));
			return;
		}
		else
		{
			ereport(ERROR,
					(errcode(ERRCODE_DUPLICATE_OBJECT),
					 errmsg("language \"%s\" already exists", languageName)));
		}
	}

	/*
	 * If we have template information for the language, ignore the supplied
	 * parameters (if any) and use the template information.
	 */
	if ((pltemplate = find_language_template(languageName)) != NULL)
	{
		List	   *funcname;

		/*
		 * Give a notice if we are ignoring supplied parameters.
		 */
		if (stmt->plhandler)
			if (Gp_role != GP_ROLE_EXECUTE)
				ereport(NOTICE,
						(errmsg("using pg_pltemplate information instead of "
								"CREATE LANGUAGE parameters")));

		/*
		 * Check permission
		 */
		if (!superuser())
		{
			if (!pltemplate->tmpldbacreate)
				ereport(ERROR,
						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
						 errmsg("must be superuser to create procedural language \"%s\"",
								languageName)));
			if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
							   get_database_name(MyDatabaseId));
		}

		/*
		 * Find or create the handler function, which we force to be in the
		 * pg_catalog schema.  If already present, it must have the correct
		 * return type.
		 */
		funcname = SystemFuncName(pltemplate->tmplhandler);
		handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
		if (OidIsValid(handlerOid))
		{
			funcrettype = get_func_rettype(handlerOid);
			if (funcrettype != LANGUAGE_HANDLEROID)
				ereport(ERROR,
						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
				  errmsg("function %s must return type \"language_handler\"",
						 NameListToString(funcname))));
		}
		else
		{
			handlerOid = ProcedureCreate(pltemplate->tmplhandler,
										 PG_CATALOG_NAMESPACE,
										 false, /* replace */
										 false, /* returnsSet */
										 LANGUAGE_HANDLEROID,
										 ClanguageId,
										 F_FMGR_C_VALIDATOR,
										 InvalidOid, /* describeFuncOid */
										 pltemplate->tmplhandler,
										 pltemplate->tmpllibrary,
										 false, /* isAgg */
										 false, /* isWin */
										 false, /* security_definer */
										 false, /* isStrict */
										 PROVOLATILE_VOLATILE,
										 buildoidvector(funcargtypes, 0),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL),
										 NIL,
										 PointerGetDatum(NULL),
										 1,
										 0,
										 PRODATAACCESS_NONE,
										 stmt->plhandlerOid);
		}

		/*
		 * Likewise for the anonymous block handler, if required; but we don't
		 * care about its return type.
		 */
		if (pltemplate->tmplinline)
		{
			funcname = SystemFuncName(pltemplate->tmplinline);
			funcargtypes[0] = INTERNALOID;
			inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
			if (!OidIsValid(inlineOid))
			{
				inlineOid = ProcedureCreate(pltemplate->tmplinline,
										 PG_CATALOG_NAMESPACE,
										 false, /* replace */
										 false, /* returnsSet */
										 VOIDOID,
										 ClanguageId,
										 F_FMGR_C_VALIDATOR,
										 InvalidOid, /* describeFuncOid */
										 pltemplate->tmplinline,
										 pltemplate->tmpllibrary,
										 false, /* isAgg */
										 false, /* isWin */
										 false, /* security_definer */
										 true, /* isStrict */
										 PROVOLATILE_IMMUTABLE,
										 buildoidvector(funcargtypes, 1),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL),
										 NIL,
										 PointerGetDatum(NULL),
										 1,
										 0,
										 PRODATAACCESS_NONE,
										 stmt->plinlineOid);

			}
		}
		else
			inlineOid = InvalidOid;

		/*
		 * Likewise for the validator, if required; but we don't care about
		 * its return type.
		 */
		if (pltemplate->tmplvalidator)
		{
			funcname = SystemFuncName(pltemplate->tmplvalidator);
			funcargtypes[0] = OIDOID;
			valOid = LookupFuncName(funcname, 1, funcargtypes, true);
			if (!OidIsValid(valOid))
			{
				valOid = ProcedureCreate(pltemplate->tmplvalidator,
										 PG_CATALOG_NAMESPACE,
										 false, /* replace */
										 false, /* returnsSet */
										 VOIDOID,
										 ClanguageId,
										 F_FMGR_C_VALIDATOR,
										 InvalidOid, /* describeFuncOid */
										 pltemplate->tmplvalidator,
										 pltemplate->tmpllibrary,
										 false, /* isAgg */
										 false, /* isWin */
										 false, /* security_definer */
										 true, /* isStrict */
										 PROVOLATILE_IMMUTABLE,
										 buildoidvector(funcargtypes, 1),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL),
										 PointerGetDatum(NULL),
										 NIL,
										 PointerGetDatum(NULL),
										 1,
										 0,
										 PRODATAACCESS_NONE,
										 stmt->plvalidatorOid);
			}
		}
		else
			valOid = InvalidOid;

		/* ok, create it */
		create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
						 valOid, pltemplate->tmpltrusted, &(stmt->plangOid));
	}
	else
	{
		/*
		 * No template, so use the provided information.  If there's no
		 * handler clause, the user is trying to rely on a template that we
		 * don't have, so complain accordingly.
		 */
		if (!stmt->plhandler)
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_OBJECT),
					 errmsg("unsupported language \"%s\"",
							languageName),
					 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));

		/*
		 * Check permission
		 */
		if (!superuser())
			ereport(ERROR,
					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
					 errmsg("must be superuser to create custom procedural language")));

		/*
		 * Lookup the PL handler function and check that it is of the expected
		 * return type
		 */
		handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
		funcrettype = get_func_rettype(handlerOid);
		if (funcrettype != LANGUAGE_HANDLEROID)
		{
			/*
			 * We allow OPAQUE just so we can load old dump files.	When we
			 * see a handler function declared OPAQUE, change it to
			 * LANGUAGE_HANDLER.  (This is probably obsolete and removable?)
			 */
			if (funcrettype == OPAQUEOID)
			{
				if (Gp_role != GP_ROLE_EXECUTE)
				ereport(WARNING,
						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
						 errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
								NameListToString(stmt->plhandler))));
				SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
			}
			else
				ereport(ERROR,
						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
				  errmsg("function %s must return type \"language_handler\"",
						 NameListToString(stmt->plhandler))));
		}

		/* validate the inline function */
		if (stmt->plinline)
		{
			funcargtypes[0] = INTERNALOID;
			inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
			/* return value is ignored, so we don't check the type */
		}
		else
			inlineOid = InvalidOid;

		/* validate the validator function */
		if (stmt->plvalidator)
		{
			funcargtypes[0] = OIDOID;
			valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
			/* return value is ignored, so we don't check the type */
		}
		else
			valOid = InvalidOid;

		/* ok, create it */
		create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
						 valOid, stmt->pltrusted, &(stmt->plangOid));
	}

	if (Gp_role == GP_ROLE_DISPATCH)
	{
		stmt->plhandlerOid = handlerOid;
		stmt->plinlineOid = inlineOid;
		stmt->plvalidatorOid = valOid;
		CdbDispatchUtilityStatement((Node *) stmt,
									DF_CANCEL_ON_ERROR|
									DF_WITH_SNAPSHOT|
									DF_NEED_TWO_PHASE,
									NULL);
	}
}