~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/commands/proclang.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * proclang.c
 
4
 *        PostgreSQL PROCEDURAL LANGUAGE support code.
 
5
 *
 
6
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 * IDENTIFICATION
 
10
 *        src/backend/commands/proclang.c
 
11
 *
 
12
 *-------------------------------------------------------------------------
 
13
 */
 
14
#include "postgres.h"
 
15
 
 
16
#include "access/genam.h"
 
17
#include "access/heapam.h"
 
18
#include "catalog/dependency.h"
 
19
#include "catalog/indexing.h"
 
20
#include "catalog/objectaccess.h"
 
21
#include "catalog/pg_language.h"
 
22
#include "catalog/pg_namespace.h"
 
23
#include "catalog/pg_pltemplate.h"
 
24
#include "catalog/pg_proc.h"
 
25
#include "catalog/pg_proc_fn.h"
 
26
#include "catalog/pg_type.h"
 
27
#include "commands/dbcommands.h"
 
28
#include "commands/defrem.h"
 
29
#include "commands/proclang.h"
 
30
#include "miscadmin.h"
 
31
#include "parser/parse_func.h"
 
32
#include "parser/parser.h"
 
33
#include "utils/acl.h"
 
34
#include "utils/builtins.h"
 
35
#include "utils/fmgroids.h"
 
36
#include "utils/lsyscache.h"
 
37
#include "utils/rel.h"
 
38
#include "utils/syscache.h"
 
39
#include "utils/tqual.h"
 
40
 
 
41
 
 
42
typedef struct
 
43
{
 
44
        bool            tmpltrusted;    /* trusted? */
 
45
        bool            tmpldbacreate;  /* db owner allowed to create? */
 
46
        char       *tmplhandler;        /* name of handler function */
 
47
        char       *tmplinline;         /* name of anonymous-block handler, or NULL */
 
48
        char       *tmplvalidator;      /* name of validator function, or NULL */
 
49
        char       *tmpllibrary;        /* path of shared library */
 
50
} PLTemplate;
 
51
 
 
52
static void create_proc_lang(const char *languageName, bool replace,
 
53
                                 Oid languageOwner, Oid handlerOid, Oid inlineOid,
 
54
                                 Oid valOid, bool trusted);
 
55
static PLTemplate *find_language_template(const char *languageName);
 
56
static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel,
 
57
                                                        Oid newOwnerId);
 
58
 
 
59
 
 
60
/* ---------------------------------------------------------------------
 
61
 * CREATE PROCEDURAL LANGUAGE
 
62
 * ---------------------------------------------------------------------
 
63
 */
 
64
void
 
65
CreateProceduralLanguage(CreatePLangStmt *stmt)
 
66
{
 
67
        char       *languageName;
 
68
        PLTemplate *pltemplate;
 
69
        Oid                     handlerOid,
 
70
                                inlineOid,
 
71
                                valOid;
 
72
        Oid                     funcrettype;
 
73
        Oid                     funcargtypes[1];
 
74
 
 
75
        /*
 
76
         * Translate the language name to lower case
 
77
         */
 
78
        languageName = case_translate_language_name(stmt->plname);
 
79
 
 
80
        /*
 
81
         * If we have template information for the language, ignore the supplied
 
82
         * parameters (if any) and use the template information.
 
83
         */
 
84
        if ((pltemplate = find_language_template(languageName)) != NULL)
 
85
        {
 
86
                List       *funcname;
 
87
 
 
88
                /*
 
89
                 * Give a notice if we are ignoring supplied parameters.
 
90
                 */
 
91
                if (stmt->plhandler)
 
92
                        ereport(NOTICE,
 
93
                                        (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
 
94
 
 
95
                /*
 
96
                 * Check permission
 
97
                 */
 
98
                if (!superuser())
 
99
                {
 
100
                        if (!pltemplate->tmpldbacreate)
 
101
                                ereport(ERROR,
 
102
                                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
103
                                                 errmsg("must be superuser to create procedural language \"%s\"",
 
104
                                                                languageName)));
 
105
                        if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
 
106
                                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
 
107
                                                           get_database_name(MyDatabaseId));
 
108
                }
 
109
 
 
110
                /*
 
111
                 * Find or create the handler function, which we force to be in the
 
112
                 * pg_catalog schema.  If already present, it must have the correct
 
113
                 * return type.
 
114
                 */
 
115
                funcname = SystemFuncName(pltemplate->tmplhandler);
 
116
                handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
 
117
                if (OidIsValid(handlerOid))
 
118
                {
 
119
                        funcrettype = get_func_rettype(handlerOid);
 
120
                        if (funcrettype != LANGUAGE_HANDLEROID)
 
121
                                ereport(ERROR,
 
122
                                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
123
                                  errmsg("function %s must return type \"language_handler\"",
 
124
                                                 NameListToString(funcname))));
 
125
                }
 
126
                else
 
127
                {
 
128
                        handlerOid = ProcedureCreate(pltemplate->tmplhandler,
 
129
                                                                                 PG_CATALOG_NAMESPACE,
 
130
                                                                                 false, /* replace */
 
131
                                                                                 false, /* returnsSet */
 
132
                                                                                 LANGUAGE_HANDLEROID,
 
133
                                                                                 ClanguageId,
 
134
                                                                                 F_FMGR_C_VALIDATOR,
 
135
                                                                                 pltemplate->tmplhandler,
 
136
                                                                                 pltemplate->tmpllibrary,
 
137
                                                                                 false, /* isAgg */
 
138
                                                                                 false, /* isWindowFunc */
 
139
                                                                                 false, /* security_definer */
 
140
                                                                                 false, /* isStrict */
 
141
                                                                                 PROVOLATILE_VOLATILE,
 
142
                                                                                 buildoidvector(funcargtypes, 0),
 
143
                                                                                 PointerGetDatum(NULL),
 
144
                                                                                 PointerGetDatum(NULL),
 
145
                                                                                 PointerGetDatum(NULL),
 
146
                                                                                 NIL,
 
147
                                                                                 PointerGetDatum(NULL),
 
148
                                                                                 1,
 
149
                                                                                 0);
 
150
                }
 
151
 
 
152
                /*
 
153
                 * Likewise for the anonymous block handler, if required; but we don't
 
154
                 * care about its return type.
 
155
                 */
 
156
                if (pltemplate->tmplinline)
 
157
                {
 
158
                        funcname = SystemFuncName(pltemplate->tmplinline);
 
159
                        funcargtypes[0] = INTERNALOID;
 
160
                        inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
 
161
                        if (!OidIsValid(inlineOid))
 
162
                        {
 
163
                                inlineOid = ProcedureCreate(pltemplate->tmplinline,
 
164
                                                                                        PG_CATALOG_NAMESPACE,
 
165
                                                                                        false,          /* replace */
 
166
                                                                                        false,          /* returnsSet */
 
167
                                                                                        VOIDOID,
 
168
                                                                                        ClanguageId,
 
169
                                                                                        F_FMGR_C_VALIDATOR,
 
170
                                                                                        pltemplate->tmplinline,
 
171
                                                                                        pltemplate->tmpllibrary,
 
172
                                                                                        false,          /* isAgg */
 
173
                                                                                        false,          /* isWindowFunc */
 
174
                                                                                        false,          /* security_definer */
 
175
                                                                                        true,           /* isStrict */
 
176
                                                                                        PROVOLATILE_VOLATILE,
 
177
                                                                                        buildoidvector(funcargtypes, 1),
 
178
                                                                                        PointerGetDatum(NULL),
 
179
                                                                                        PointerGetDatum(NULL),
 
180
                                                                                        PointerGetDatum(NULL),
 
181
                                                                                        NIL,
 
182
                                                                                        PointerGetDatum(NULL),
 
183
                                                                                        1,
 
184
                                                                                        0);
 
185
                        }
 
186
                }
 
187
                else
 
188
                        inlineOid = InvalidOid;
 
189
 
 
190
                /*
 
191
                 * Likewise for the validator, if required; but we don't care about
 
192
                 * its return type.
 
193
                 */
 
194
                if (pltemplate->tmplvalidator)
 
195
                {
 
196
                        funcname = SystemFuncName(pltemplate->tmplvalidator);
 
197
                        funcargtypes[0] = OIDOID;
 
198
                        valOid = LookupFuncName(funcname, 1, funcargtypes, true);
 
199
                        if (!OidIsValid(valOid))
 
200
                        {
 
201
                                valOid = ProcedureCreate(pltemplate->tmplvalidator,
 
202
                                                                                 PG_CATALOG_NAMESPACE,
 
203
                                                                                 false, /* replace */
 
204
                                                                                 false, /* returnsSet */
 
205
                                                                                 VOIDOID,
 
206
                                                                                 ClanguageId,
 
207
                                                                                 F_FMGR_C_VALIDATOR,
 
208
                                                                                 pltemplate->tmplvalidator,
 
209
                                                                                 pltemplate->tmpllibrary,
 
210
                                                                                 false, /* isAgg */
 
211
                                                                                 false, /* isWindowFunc */
 
212
                                                                                 false, /* security_definer */
 
213
                                                                                 true,  /* isStrict */
 
214
                                                                                 PROVOLATILE_VOLATILE,
 
215
                                                                                 buildoidvector(funcargtypes, 1),
 
216
                                                                                 PointerGetDatum(NULL),
 
217
                                                                                 PointerGetDatum(NULL),
 
218
                                                                                 PointerGetDatum(NULL),
 
219
                                                                                 NIL,
 
220
                                                                                 PointerGetDatum(NULL),
 
221
                                                                                 1,
 
222
                                                                                 0);
 
223
                        }
 
224
                }
 
225
                else
 
226
                        valOid = InvalidOid;
 
227
 
 
228
                /* ok, create it */
 
229
                create_proc_lang(languageName, stmt->replace, GetUserId(),
 
230
                                                 handlerOid, inlineOid,
 
231
                                                 valOid, pltemplate->tmpltrusted);
 
232
        }
 
233
        else
 
234
        {
 
235
                /*
 
236
                 * No template, so use the provided information.  If there's no
 
237
                 * handler clause, the user is trying to rely on a template that we
 
238
                 * don't have, so complain accordingly.
 
239
                 */
 
240
                if (!stmt->plhandler)
 
241
                        ereport(ERROR,
 
242
                                        (errcode(ERRCODE_UNDEFINED_OBJECT),
 
243
                                         errmsg("unsupported language \"%s\"",
 
244
                                                        languageName),
 
245
                                         errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
 
246
 
 
247
                /*
 
248
                 * Check permission
 
249
                 */
 
250
                if (!superuser())
 
251
                        ereport(ERROR,
 
252
                                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
253
                                         errmsg("must be superuser to create custom procedural language")));
 
254
 
 
255
                /*
 
256
                 * Lookup the PL handler function and check that it is of the expected
 
257
                 * return type
 
258
                 */
 
259
                handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
 
260
                funcrettype = get_func_rettype(handlerOid);
 
261
                if (funcrettype != LANGUAGE_HANDLEROID)
 
262
                {
 
263
                        /*
 
264
                         * We allow OPAQUE just so we can load old dump files.  When we
 
265
                         * see a handler function declared OPAQUE, change it to
 
266
                         * LANGUAGE_HANDLER.  (This is probably obsolete and removable?)
 
267
                         */
 
268
                        if (funcrettype == OPAQUEOID)
 
269
                        {
 
270
                                ereport(WARNING,
 
271
                                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
272
                                                 errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
 
273
                                                                NameListToString(stmt->plhandler))));
 
274
                                SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
 
275
                        }
 
276
                        else
 
277
                                ereport(ERROR,
 
278
                                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
279
                                  errmsg("function %s must return type \"language_handler\"",
 
280
                                                 NameListToString(stmt->plhandler))));
 
281
                }
 
282
 
 
283
                /* validate the inline function */
 
284
                if (stmt->plinline)
 
285
                {
 
286
                        funcargtypes[0] = INTERNALOID;
 
287
                        inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
 
288
                        /* return value is ignored, so we don't check the type */
 
289
                }
 
290
                else
 
291
                        inlineOid = InvalidOid;
 
292
 
 
293
                /* validate the validator function */
 
294
                if (stmt->plvalidator)
 
295
                {
 
296
                        funcargtypes[0] = OIDOID;
 
297
                        valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
 
298
                        /* return value is ignored, so we don't check the type */
 
299
                }
 
300
                else
 
301
                        valOid = InvalidOid;
 
302
 
 
303
                /* ok, create it */
 
304
                create_proc_lang(languageName, stmt->replace, GetUserId(),
 
305
                                                 handlerOid, inlineOid,
 
306
                                                 valOid, stmt->pltrusted);
 
307
        }
 
308
}
 
309
 
 
310
/*
 
311
 * Guts of language creation.
 
312
 */
 
313
static void
 
314
create_proc_lang(const char *languageName, bool replace,
 
315
                                 Oid languageOwner, Oid handlerOid, Oid inlineOid,
 
316
                                 Oid valOid, bool trusted)
 
317
{
 
318
        Relation        rel;
 
319
        TupleDesc       tupDesc;
 
320
        Datum           values[Natts_pg_language];
 
321
        bool            nulls[Natts_pg_language];
 
322
        bool            replaces[Natts_pg_language];
 
323
        NameData        langname;
 
324
        HeapTuple       oldtup;
 
325
        HeapTuple       tup;
 
326
        bool            is_update;
 
327
        ObjectAddress myself,
 
328
                                referenced;
 
329
 
 
330
        rel = heap_open(LanguageRelationId, RowExclusiveLock);
 
331
        tupDesc = RelationGetDescr(rel);
 
332
 
 
333
        /* Prepare data to be inserted */
 
334
        memset(values, 0, sizeof(values));
 
335
        memset(nulls, false, sizeof(nulls));
 
336
        memset(replaces, true, sizeof(replaces));
 
337
 
 
338
        namestrcpy(&langname, languageName);
 
339
        values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
 
340
        values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
 
341
        values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
 
342
        values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
 
343
        values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
 
344
        values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
 
345
        values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
 
346
        nulls[Anum_pg_language_lanacl - 1] = true;
 
347
 
 
348
        /* Check for pre-existing definition */
 
349
        oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
 
350
 
 
351
        if (HeapTupleIsValid(oldtup))
 
352
        {
 
353
                /* There is one; okay to replace it? */
 
354
                if (!replace)
 
355
                        ereport(ERROR,
 
356
                                        (errcode(ERRCODE_DUPLICATE_OBJECT),
 
357
                                         errmsg("language \"%s\" already exists", languageName)));
 
358
                if (!pg_language_ownercheck(HeapTupleGetOid(oldtup), languageOwner))
 
359
                        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
 
360
                                                   languageName);
 
361
 
 
362
                /*
 
363
                 * Do not change existing ownership or permissions.  Note
 
364
                 * dependency-update code below has to agree with this decision.
 
365
                 */
 
366
                replaces[Anum_pg_language_lanowner - 1] = false;
 
367
                replaces[Anum_pg_language_lanacl - 1] = false;
 
368
 
 
369
                /* Okay, do it... */
 
370
                tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
 
371
                simple_heap_update(rel, &tup->t_self, tup);
 
372
 
 
373
                ReleaseSysCache(oldtup);
 
374
                is_update = true;
 
375
        }
 
376
        else
 
377
        {
 
378
                /* Creating a new language */
 
379
                tup = heap_form_tuple(tupDesc, values, nulls);
 
380
                simple_heap_insert(rel, tup);
 
381
                is_update = false;
 
382
        }
 
383
 
 
384
        /* Need to update indexes for either the insert or update case */
 
385
        CatalogUpdateIndexes(rel, tup);
 
386
 
 
387
        /*
 
388
         * Create dependencies for the new language.  If we are updating an
 
389
         * existing language, first delete any existing pg_depend entries.
 
390
         * (However, since we are not changing ownership or permissions, the
 
391
         * shared dependencies do *not* need to change, and we leave them alone.
 
392
         * We also don't change any pre-existing extension-membership dependency.)
 
393
         */
 
394
        myself.classId = LanguageRelationId;
 
395
        myself.objectId = HeapTupleGetOid(tup);
 
396
        myself.objectSubId = 0;
 
397
 
 
398
        if (is_update)
 
399
                deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
 
400
 
 
401
        /* dependency on owner of language */
 
402
        if (!is_update)
 
403
                recordDependencyOnOwner(myself.classId, myself.objectId,
 
404
                                                                languageOwner);
 
405
 
 
406
        /* dependency on extension */
 
407
        if (!is_update)
 
408
                recordDependencyOnCurrentExtension(&myself);
 
409
 
 
410
        /* dependency on the PL handler function */
 
411
        referenced.classId = ProcedureRelationId;
 
412
        referenced.objectId = handlerOid;
 
413
        referenced.objectSubId = 0;
 
414
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
415
 
 
416
        /* dependency on the inline handler function, if any */
 
417
        if (OidIsValid(inlineOid))
 
418
        {
 
419
                referenced.classId = ProcedureRelationId;
 
420
                referenced.objectId = inlineOid;
 
421
                referenced.objectSubId = 0;
 
422
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
423
        }
 
424
 
 
425
        /* dependency on the validator function, if any */
 
426
        if (OidIsValid(valOid))
 
427
        {
 
428
                referenced.classId = ProcedureRelationId;
 
429
                referenced.objectId = valOid;
 
430
                referenced.objectSubId = 0;
 
431
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
432
        }
 
433
 
 
434
        /* Post creation hook for new procedural language */
 
435
        InvokeObjectAccessHook(OAT_POST_CREATE,
 
436
                                                   LanguageRelationId, myself.objectId, 0);
 
437
 
 
438
        heap_close(rel, RowExclusiveLock);
 
439
}
 
440
 
 
441
/*
 
442
 * Look to see if we have template information for the given language name.
 
443
 */
 
444
static PLTemplate *
 
445
find_language_template(const char *languageName)
 
446
{
 
447
        PLTemplate *result;
 
448
        Relation        rel;
 
449
        SysScanDesc scan;
 
450
        ScanKeyData key;
 
451
        HeapTuple       tup;
 
452
 
 
453
        rel = heap_open(PLTemplateRelationId, AccessShareLock);
 
454
 
 
455
        ScanKeyInit(&key,
 
456
                                Anum_pg_pltemplate_tmplname,
 
457
                                BTEqualStrategyNumber, F_NAMEEQ,
 
458
                                NameGetDatum(languageName));
 
459
        scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
 
460
                                                          SnapshotNow, 1, &key);
 
461
 
 
462
        tup = systable_getnext(scan);
 
463
        if (HeapTupleIsValid(tup))
 
464
        {
 
465
                Form_pg_pltemplate tmpl = (Form_pg_pltemplate) GETSTRUCT(tup);
 
466
                Datum           datum;
 
467
                bool            isnull;
 
468
 
 
469
                result = (PLTemplate *) palloc0(sizeof(PLTemplate));
 
470
                result->tmpltrusted = tmpl->tmpltrusted;
 
471
                result->tmpldbacreate = tmpl->tmpldbacreate;
 
472
 
 
473
                /* Remaining fields are variable-width so we need heap_getattr */
 
474
                datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
 
475
                                                         RelationGetDescr(rel), &isnull);
 
476
                if (!isnull)
 
477
                        result->tmplhandler = TextDatumGetCString(datum);
 
478
 
 
479
                datum = heap_getattr(tup, Anum_pg_pltemplate_tmplinline,
 
480
                                                         RelationGetDescr(rel), &isnull);
 
481
                if (!isnull)
 
482
                        result->tmplinline = TextDatumGetCString(datum);
 
483
 
 
484
                datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
 
485
                                                         RelationGetDescr(rel), &isnull);
 
486
                if (!isnull)
 
487
                        result->tmplvalidator = TextDatumGetCString(datum);
 
488
 
 
489
                datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary,
 
490
                                                         RelationGetDescr(rel), &isnull);
 
491
                if (!isnull)
 
492
                        result->tmpllibrary = TextDatumGetCString(datum);
 
493
 
 
494
                /* Ignore template if handler or library info is missing */
 
495
                if (!result->tmplhandler || !result->tmpllibrary)
 
496
                        result = NULL;
 
497
        }
 
498
        else
 
499
                result = NULL;
 
500
 
 
501
        systable_endscan(scan);
 
502
 
 
503
        heap_close(rel, AccessShareLock);
 
504
 
 
505
        return result;
 
506
}
 
507
 
 
508
 
 
509
/*
 
510
 * This just returns TRUE if we have a valid template for a given language
 
511
 */
 
512
bool
 
513
PLTemplateExists(const char *languageName)
 
514
{
 
515
        return (find_language_template(languageName) != NULL);
 
516
}
 
517
 
 
518
 
 
519
/* ---------------------------------------------------------------------
 
520
 * DROP PROCEDURAL LANGUAGE
 
521
 * ---------------------------------------------------------------------
 
522
 */
 
523
void
 
524
DropProceduralLanguage(DropPLangStmt *stmt)
 
525
{
 
526
        char       *languageName;
 
527
        Oid                     oid;
 
528
        ObjectAddress object;
 
529
 
 
530
        /*
 
531
         * Translate the language name, check that the language exists
 
532
         */
 
533
        languageName = case_translate_language_name(stmt->plname);
 
534
 
 
535
        oid = get_language_oid(languageName, stmt->missing_ok);
 
536
        if (!OidIsValid(oid))
 
537
        {
 
538
                ereport(NOTICE,
 
539
                                (errmsg("language \"%s\" does not exist, skipping",
 
540
                                                languageName)));
 
541
                return;
 
542
        }
 
543
 
 
544
        /*
 
545
         * Check permission
 
546
         */
 
547
        if (!pg_language_ownercheck(oid, GetUserId()))
 
548
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
 
549
                                           languageName);
 
550
 
 
551
        object.classId = LanguageRelationId;
 
552
        object.objectId = oid;
 
553
        object.objectSubId = 0;
 
554
 
 
555
        /*
 
556
         * Do the deletion
 
557
         */
 
558
        performDeletion(&object, stmt->behavior);
 
559
}
 
560
 
 
561
/*
 
562
 * Guts of language dropping.
 
563
 */
 
564
void
 
565
DropProceduralLanguageById(Oid langOid)
 
566
{
 
567
        Relation        rel;
 
568
        HeapTuple       langTup;
 
569
 
 
570
        rel = heap_open(LanguageRelationId, RowExclusiveLock);
 
571
 
 
572
        langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(langOid));
 
573
        if (!HeapTupleIsValid(langTup))         /* should not happen */
 
574
                elog(ERROR, "cache lookup failed for language %u", langOid);
 
575
 
 
576
        simple_heap_delete(rel, &langTup->t_self);
 
577
 
 
578
        ReleaseSysCache(langTup);
 
579
 
 
580
        heap_close(rel, RowExclusiveLock);
 
581
}
 
582
 
 
583
/*
 
584
 * Rename language
 
585
 */
 
586
void
 
587
RenameLanguage(const char *oldname, const char *newname)
 
588
{
 
589
        HeapTuple       tup;
 
590
        Relation        rel;
 
591
 
 
592
        /* Translate both names for consistency with CREATE */
 
593
        oldname = case_translate_language_name(oldname);
 
594
        newname = case_translate_language_name(newname);
 
595
 
 
596
        rel = heap_open(LanguageRelationId, RowExclusiveLock);
 
597
 
 
598
        tup = SearchSysCacheCopy1(LANGNAME, CStringGetDatum(oldname));
 
599
        if (!HeapTupleIsValid(tup))
 
600
                ereport(ERROR,
 
601
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
602
                                 errmsg("language \"%s\" does not exist", oldname)));
 
603
 
 
604
        /* make sure the new name doesn't exist */
 
605
        if (SearchSysCacheExists1(LANGNAME, CStringGetDatum(newname)))
 
606
                ereport(ERROR,
 
607
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
 
608
                                 errmsg("language \"%s\" already exists", newname)));
 
609
 
 
610
        /* must be owner of PL */
 
611
        if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
 
612
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
 
613
                                           oldname);
 
614
 
 
615
        /* rename */
 
616
        namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
 
617
        simple_heap_update(rel, &tup->t_self, tup);
 
618
        CatalogUpdateIndexes(rel, tup);
 
619
 
 
620
        heap_close(rel, NoLock);
 
621
        heap_freetuple(tup);
 
622
}
 
623
 
 
624
/*
 
625
 * Change language owner
 
626
 */
 
627
void
 
628
AlterLanguageOwner(const char *name, Oid newOwnerId)
 
629
{
 
630
        HeapTuple       tup;
 
631
        Relation        rel;
 
632
 
 
633
        /* Translate name for consistency with CREATE */
 
634
        name = case_translate_language_name(name);
 
635
 
 
636
        rel = heap_open(LanguageRelationId, RowExclusiveLock);
 
637
 
 
638
        tup = SearchSysCache1(LANGNAME, CStringGetDatum(name));
 
639
        if (!HeapTupleIsValid(tup))
 
640
                ereport(ERROR,
 
641
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
642
                                 errmsg("language \"%s\" does not exist", name)));
 
643
 
 
644
        AlterLanguageOwner_internal(tup, rel, newOwnerId);
 
645
 
 
646
        ReleaseSysCache(tup);
 
647
 
 
648
        heap_close(rel, RowExclusiveLock);
 
649
 
 
650
}
 
651
 
 
652
/*
 
653
 * Change language owner, specified by OID
 
654
 */
 
655
void
 
656
AlterLanguageOwner_oid(Oid oid, Oid newOwnerId)
 
657
{
 
658
        HeapTuple       tup;
 
659
        Relation        rel;
 
660
 
 
661
        rel = heap_open(LanguageRelationId, RowExclusiveLock);
 
662
 
 
663
        tup = SearchSysCache1(LANGOID, ObjectIdGetDatum(oid));
 
664
        if (!HeapTupleIsValid(tup))
 
665
                elog(ERROR, "cache lookup failed for language %u", oid);
 
666
 
 
667
        AlterLanguageOwner_internal(tup, rel, newOwnerId);
 
668
 
 
669
        ReleaseSysCache(tup);
 
670
 
 
671
        heap_close(rel, RowExclusiveLock);
 
672
}
 
673
 
 
674
/*
 
675
 * Workhorse for AlterLanguageOwner variants
 
676
 */
 
677
static void
 
678
AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
 
679
{
 
680
        Form_pg_language lanForm;
 
681
 
 
682
        lanForm = (Form_pg_language) GETSTRUCT(tup);
 
683
 
 
684
        /*
 
685
         * If the new owner is the same as the existing owner, consider the
 
686
         * command to have succeeded.  This is for dump restoration purposes.
 
687
         */
 
688
        if (lanForm->lanowner != newOwnerId)
 
689
        {
 
690
                Datum           repl_val[Natts_pg_language];
 
691
                bool            repl_null[Natts_pg_language];
 
692
                bool            repl_repl[Natts_pg_language];
 
693
                Acl                *newAcl;
 
694
                Datum           aclDatum;
 
695
                bool            isNull;
 
696
                HeapTuple       newtuple;
 
697
 
 
698
                /* Otherwise, must be owner of the existing object */
 
699
                if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
 
700
                        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
 
701
                                                   NameStr(lanForm->lanname));
 
702
 
 
703
                /* Must be able to become new owner */
 
704
                check_is_member_of_role(GetUserId(), newOwnerId);
 
705
 
 
706
                memset(repl_null, false, sizeof(repl_null));
 
707
                memset(repl_repl, false, sizeof(repl_repl));
 
708
 
 
709
                repl_repl[Anum_pg_language_lanowner - 1] = true;
 
710
                repl_val[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(newOwnerId);
 
711
 
 
712
                /*
 
713
                 * Determine the modified ACL for the new owner.  This is only
 
714
                 * necessary when the ACL is non-null.
 
715
                 */
 
716
                aclDatum = SysCacheGetAttr(LANGNAME, tup,
 
717
                                                                   Anum_pg_language_lanacl,
 
718
                                                                   &isNull);
 
719
                if (!isNull)
 
720
                {
 
721
                        newAcl = aclnewowner(DatumGetAclP(aclDatum),
 
722
                                                                 lanForm->lanowner, newOwnerId);
 
723
                        repl_repl[Anum_pg_language_lanacl - 1] = true;
 
724
                        repl_val[Anum_pg_language_lanacl - 1] = PointerGetDatum(newAcl);
 
725
                }
 
726
 
 
727
                newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
 
728
                                                                         repl_val, repl_null, repl_repl);
 
729
 
 
730
                simple_heap_update(rel, &newtuple->t_self, newtuple);
 
731
                CatalogUpdateIndexes(rel, newtuple);
 
732
 
 
733
                heap_freetuple(newtuple);
 
734
 
 
735
                /* Update owner dependency reference */
 
736
                changeDependencyOnOwner(LanguageRelationId, HeapTupleGetOid(tup),
 
737
                                                                newOwnerId);
 
738
        }
 
739
}
 
740
 
 
741
/*
 
742
 * get_language_oid - given a language name, look up the OID
 
743
 *
 
744
 * If missing_ok is false, throw an error if language name not found.  If
 
745
 * true, just return InvalidOid.
 
746
 */
 
747
Oid
 
748
get_language_oid(const char *langname, bool missing_ok)
 
749
{
 
750
        Oid                     oid;
 
751
 
 
752
        oid = GetSysCacheOid1(LANGNAME, CStringGetDatum(langname));
 
753
        if (!OidIsValid(oid) && !missing_ok)
 
754
                ereport(ERROR,
 
755
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
756
                                 errmsg("language \"%s\" does not exist", langname)));
 
757
        return oid;
 
758
}