Skip to content
Snippets Groups Projects
Select Git revision
  • benchmark-tools
  • postgres-lambda
  • master default
  • REL9_4_25
  • REL9_5_20
  • REL9_6_16
  • REL_10_11
  • REL_11_6
  • REL_12_1
  • REL_12_0
  • REL_12_RC1
  • REL_12_BETA4
  • REL9_4_24
  • REL9_5_19
  • REL9_6_15
  • REL_10_10
  • REL_11_5
  • REL_12_BETA3
  • REL9_4_23
  • REL9_5_18
  • REL9_6_14
  • REL_10_9
  • REL_11_4
23 results

proclang.c

Blame
  • proclang.c 7.11 KiB
    /*-------------------------------------------------------------------------
     *
     * proclang.c
     *	  PostgreSQL PROCEDURAL LANGUAGE support code.
     *
     * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
     * Portions Copyright (c) 1994, Regents of the University of California
     *
     * IDENTIFICATION
     *	  $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.53 2004/02/21 00:34:52 tgl Exp $
     *
     *-------------------------------------------------------------------------
     */
    #include "postgres.h"
    
    #include <ctype.h>
    
    #include "access/heapam.h"
    #include "catalog/catname.h"
    #include "catalog/dependency.h"
    #include "catalog/indexing.h"
    #include "catalog/namespace.h"
    #include "catalog/pg_language.h"
    #include "catalog/pg_proc.h"
    #include "catalog/pg_type.h"
    #include "commands/proclang.h"
    #include "commands/defrem.h"
    #include "fmgr.h"
    #include "miscadmin.h"
    #include "parser/parse_func.h"
    #include "utils/builtins.h"
    #include "utils/lsyscache.h"
    #include "utils/syscache.h"
    
    
    /* ---------------------------------------------------------------------
     * CREATE PROCEDURAL LANGUAGE
     * ---------------------------------------------------------------------
     */
    void
    CreateProceduralLanguage(CreatePLangStmt *stmt)
    {
    	char	   *languageName;
    	Oid			procOid,
    				valProcOid;
    	Oid			funcrettype;
    	Oid			typev[FUNC_MAX_ARGS];
    	NameData	langname;
    	char		nulls[Natts_pg_language];
    	Datum		values[Natts_pg_language];
    	Relation	rel;
    	HeapTuple	tup;
    	TupleDesc	tupDesc;
    	int			i;
    	ObjectAddress myself,
    				referenced;
    
    	/*
    	 * 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)));
    
    	/*
    	 * Lookup the PL handler function and check that it is of the expected
    	 * return type
    	 */
    	MemSet(typev, 0, sizeof(typev));
    	procOid = LookupFuncName(stmt->plhandler, 0, typev, false);
    	funcrettype = get_func_rettype(procOid);
    	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.
    		 */
    		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(procOid, 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)
    	{
    		typev[0] = OIDOID;
    		valProcOid = LookupFuncName(stmt->plvalidator, 1, typev, false);
    		/* return value is ignored, so we don't check the type */
    	}
    	else
    		valProcOid = InvalidOid;
    
    	/*
    	 * Insert the new language into pg_language
    	 */
    	for (i = 0; i < Natts_pg_language; i++)
    	{
    		nulls[i] = ' ';
    		values[i] = (Datum) NULL;
    	}
    
    	i = 0;
    	namestrcpy(&langname, languageName);
    	values[i++] = NameGetDatum(&langname);			/* lanname */
    	values[i++] = BoolGetDatum(true);				/* lanispl */
    	values[i++] = BoolGetDatum(stmt->pltrusted);	/* lanpltrusted */
    	values[i++] = ObjectIdGetDatum(procOid);		/* lanplcallfoid */
    	values[i++] = ObjectIdGetDatum(valProcOid);		/* lanvalidator */
    	nulls[i] = 'n';									/* lanacl */
    
    	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
    
    	tupDesc = rel->rd_att;
    	tup = heap_formtuple(tupDesc, values, nulls);
    
    	simple_heap_insert(rel, tup);
    
    	CatalogUpdateIndexes(rel, tup);
    
    	/*
    	 * Create dependencies for language
    	 */
    	myself.classId = RelationGetRelid(rel);
    	myself.objectId = HeapTupleGetOid(tup);
    	myself.objectSubId = 0;
    
    	/* dependency on the PL handler function */
    	referenced.classId = RelOid_pg_proc;
    	referenced.objectId = procOid;
    	referenced.objectSubId = 0;
    	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    
    	/* dependency on the validator function, if any */
    	if (OidIsValid(valProcOid))
    	{
    		referenced.classId = RelOid_pg_proc;
    		referenced.objectId = valProcOid;
    		referenced.objectSubId = 0;
    		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    	}
    
    	heap_close(rel, RowExclusiveLock);
    }
    
    
    /* ---------------------------------------------------------------------
     * 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 this language exist and is
    	 * a PL
    	 */
    	languageName = case_translate_language_name(stmt->plname);
    
    	langTup = SearchSysCache(LANGNAME,
    							 CStringGetDatum(languageName),
    							 0, 0, 0);
    	if (!HeapTupleIsValid(langTup))
    		ereport(ERROR,
    				(errcode(ERRCODE_UNDEFINED_OBJECT),
    				 errmsg("language \"%s\" does not exist", languageName)));
    
    	object.classId = get_system_catalog_relid(LanguageRelationName);
    	object.objectId = HeapTupleGetOid(langTup);
    	object.objectSubId = 0;
    
    	ReleaseSysCache(langTup);
    
    	/*
    	 * Do the deletion
    	 */
    	performDeletion(&object, stmt->behavior);
    }
    
    /*
     * Guts of language dropping.
     */
    void
    DropProceduralLanguageById(Oid langOid)
    {
    	Relation	rel;
    	HeapTuple	langTup;
    
    	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
    
    	langTup = SearchSysCache(LANGOID,
    							 ObjectIdGetDatum(langOid),
    							 0, 0, 0);
    	if (!HeapTupleIsValid(langTup))		/* should not happen */
    		elog(ERROR, "cache lookup failed for language %u", langOid);
    
    	simple_heap_delete(rel, &langTup->t_self);
    
    	ReleaseSysCache(langTup);
    
    	heap_close(rel, RowExclusiveLock);
    }
    
    /*
     * Rename language
     */
    void
    RenameLanguage(const char *oldname, const char *newname)
    {
    	HeapTuple	tup;
    	Relation	rel;
    
    	rel = heap_openr(ShadowRelationName, 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 */
    	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);
    }