mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-30 07:41:15 +02:00
b0f5086e41
bitmap, if present). Per Tom Lane's suggestion the information whether a tuple has an oid or not is carried in the tuple descriptor. For debugging reasons tdhasoid is of type char, not bool. There are predefined values for WITHOID, WITHOUTOID and UNDEFOID. This patch has been generated against a cvs snapshot from last week and I don't expect it to apply cleanly to current sources. While I post it here for public review, I'm working on a new version against a current snapshot. (There's been heavy activity recently; hope to catch up some day ...) This is a long patch; if it is too hard to swallow, I can provide it in smaller pieces: Part 1: Accessor macros Part 2: tdhasoid in TupDesc Part 3: Regression test Part 4: Parameter withoid to heap_addheader Part 5: Eliminate t_oid from HeapTupleHeader Part 2 is the most hairy part because of changes in the executor and even in the parser; the other parts are straightforward. Up to part 4 the patched postmaster stays binary compatible to databases created with an unpatched version. Part 5 is small (100 lines) and finally breaks compatibility. Manfred Koizar
229 lines
5.9 KiB
C
229 lines
5.9 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* proclang.c
|
|
* PostgreSQL PROCEDURAL LANGUAGE support code.
|
|
*
|
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* IDENTIFICATION
|
|
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.37 2002/07/20 05:16:57 momjian 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[NAMEDATALEN];
|
|
Oid procOid, valProcOid;
|
|
Oid typev[FUNC_MAX_ARGS];
|
|
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())
|
|
elog(ERROR, "Only users with Postgres superuser privilege are "
|
|
"permitted to create procedural languages");
|
|
|
|
/*
|
|
* Translate the language name and check that this language doesn't
|
|
* already exist
|
|
*/
|
|
case_translate_language_name(stmt->plname, languageName);
|
|
|
|
if (SearchSysCacheExists(LANGNAME,
|
|
PointerGetDatum(languageName),
|
|
0, 0, 0))
|
|
elog(ERROR, "Language %s already exists", languageName);
|
|
|
|
/*
|
|
* Lookup the PL handler function and check that it is of return type
|
|
* Opaque
|
|
*/
|
|
MemSet(typev, 0, sizeof(typev));
|
|
procOid = LookupFuncName(stmt->plhandler, 0, typev);
|
|
if (!OidIsValid(procOid))
|
|
elog(ERROR, "PL handler function %s() doesn't exist",
|
|
NameListToString(stmt->plhandler));
|
|
if (get_func_rettype(procOid) != InvalidOid)
|
|
elog(ERROR, "PL handler function %s() does not return type \"opaque\"",
|
|
NameListToString(stmt->plhandler));
|
|
|
|
/* validate the validator function */
|
|
if (stmt->plvalidator)
|
|
{
|
|
typev[0] = OIDOID;
|
|
valProcOid = LookupFuncName(stmt->plvalidator, 1, typev);
|
|
if (!OidIsValid(valProcOid))
|
|
elog(ERROR, "PL validator function %s(oid) doesn't exist",
|
|
NameListToString(stmt->plvalidator));
|
|
}
|
|
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;
|
|
values[i++] = PointerGetDatum(languageName);
|
|
values[i++] = BoolGetDatum(true); /* lanispl */
|
|
values[i++] = BoolGetDatum(stmt->pltrusted);
|
|
values[i++] = ObjectIdGetDatum(procOid);
|
|
values[i++] = ObjectIdGetDatum(valProcOid);
|
|
values[i++] = DirectFunctionCall1(textin,
|
|
CStringGetDatum(stmt->plcompiler));
|
|
nulls[i] = 'n'; /* lanacl */
|
|
|
|
rel = heap_openr(LanguageRelationName, RowExclusiveLock);
|
|
|
|
tupDesc = rel->rd_att;
|
|
tup = heap_formtuple(tupDesc, values, nulls);
|
|
|
|
simple_heap_insert(rel, tup);
|
|
|
|
if (RelationGetForm(rel)->relhasindex)
|
|
{
|
|
Relation idescs[Num_pg_language_indices];
|
|
|
|
CatalogOpenIndices(Num_pg_language_indices, Name_pg_language_indices, idescs);
|
|
CatalogIndexInsert(idescs, Num_pg_language_indices, rel, tup);
|
|
CatalogCloseIndices(Num_pg_language_indices, idescs);
|
|
}
|
|
|
|
/*
|
|
* 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[NAMEDATALEN];
|
|
HeapTuple langTup;
|
|
ObjectAddress object;
|
|
|
|
/*
|
|
* Check permission
|
|
*/
|
|
if (!superuser())
|
|
elog(ERROR, "Only users with Postgres superuser privilege are "
|
|
"permitted to drop procedural languages");
|
|
|
|
/*
|
|
* Translate the language name, check that this language exist and is
|
|
* a PL
|
|
*/
|
|
case_translate_language_name(stmt->plname, languageName);
|
|
|
|
langTup = SearchSysCache(LANGNAME,
|
|
CStringGetDatum(languageName),
|
|
0, 0, 0);
|
|
if (!HeapTupleIsValid(langTup))
|
|
elog(ERROR, "Language %s doesn't exist", languageName);
|
|
|
|
if (!((Form_pg_language) GETSTRUCT(langTup))->lanispl)
|
|
elog(ERROR, "Language %s isn't a created procedural language",
|
|
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))
|
|
elog(ERROR, "DropProceduralLanguageById: language %u not found",
|
|
langOid);
|
|
|
|
simple_heap_delete(rel, &langTup->t_self);
|
|
|
|
ReleaseSysCache(langTup);
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
|
}
|