00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "access/genam.h"
00017 #include "access/heapam.h"
00018 #include "access/htup_details.h"
00019 #include "catalog/dependency.h"
00020 #include "catalog/indexing.h"
00021 #include "catalog/objectaccess.h"
00022 #include "catalog/pg_authid.h"
00023 #include "catalog/pg_language.h"
00024 #include "catalog/pg_namespace.h"
00025 #include "catalog/pg_pltemplate.h"
00026 #include "catalog/pg_proc.h"
00027 #include "catalog/pg_proc_fn.h"
00028 #include "catalog/pg_type.h"
00029 #include "commands/dbcommands.h"
00030 #include "commands/defrem.h"
00031 #include "commands/proclang.h"
00032 #include "miscadmin.h"
00033 #include "parser/parse_func.h"
00034 #include "parser/parser.h"
00035 #include "utils/acl.h"
00036 #include "utils/builtins.h"
00037 #include "utils/fmgroids.h"
00038 #include "utils/lsyscache.h"
00039 #include "utils/rel.h"
00040 #include "utils/syscache.h"
00041 #include "utils/tqual.h"
00042
00043
00044 typedef struct
00045 {
00046 bool tmpltrusted;
00047 bool tmpldbacreate;
00048 char *tmplhandler;
00049 char *tmplinline;
00050 char *tmplvalidator;
00051 char *tmpllibrary;
00052 } PLTemplate;
00053
00054 static Oid create_proc_lang(const char *languageName, bool replace,
00055 Oid languageOwner, Oid handlerOid, Oid inlineOid,
00056 Oid valOid, bool trusted);
00057 static PLTemplate *find_language_template(const char *languageName);
00058
00059
00060
00061
00062
00063 Oid
00064 CreateProceduralLanguage(CreatePLangStmt *stmt)
00065 {
00066 PLTemplate *pltemplate;
00067 Oid handlerOid,
00068 inlineOid,
00069 valOid;
00070 Oid funcrettype;
00071 Oid funcargtypes[1];
00072
00073
00074
00075
00076
00077 if ((pltemplate = find_language_template(stmt->plname)) != NULL)
00078 {
00079 List *funcname;
00080
00081
00082
00083
00084 if (stmt->plhandler)
00085 ereport(NOTICE,
00086 (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
00087
00088
00089
00090
00091 if (!superuser())
00092 {
00093 if (!pltemplate->tmpldbacreate)
00094 ereport(ERROR,
00095 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00096 errmsg("must be superuser to create procedural language \"%s\"",
00097 stmt->plname)));
00098 if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
00099 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
00100 get_database_name(MyDatabaseId));
00101 }
00102
00103
00104
00105
00106
00107
00108 funcname = SystemFuncName(pltemplate->tmplhandler);
00109 handlerOid = LookupFuncName(funcname, 0, funcargtypes, true);
00110 if (OidIsValid(handlerOid))
00111 {
00112 funcrettype = get_func_rettype(handlerOid);
00113 if (funcrettype != LANGUAGE_HANDLEROID)
00114 ereport(ERROR,
00115 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00116 errmsg("function %s must return type \"language_handler\"",
00117 NameListToString(funcname))));
00118 }
00119 else
00120 {
00121 handlerOid = ProcedureCreate(pltemplate->tmplhandler,
00122 PG_CATALOG_NAMESPACE,
00123 false,
00124 false,
00125 LANGUAGE_HANDLEROID,
00126 BOOTSTRAP_SUPERUSERID,
00127 ClanguageId,
00128 F_FMGR_C_VALIDATOR,
00129 pltemplate->tmplhandler,
00130 pltemplate->tmpllibrary,
00131 false,
00132 false,
00133 false,
00134 false,
00135 false,
00136 PROVOLATILE_VOLATILE,
00137 buildoidvector(funcargtypes, 0),
00138 PointerGetDatum(NULL),
00139 PointerGetDatum(NULL),
00140 PointerGetDatum(NULL),
00141 NIL,
00142 PointerGetDatum(NULL),
00143 1,
00144 0);
00145 }
00146
00147
00148
00149
00150
00151 if (pltemplate->tmplinline)
00152 {
00153 funcname = SystemFuncName(pltemplate->tmplinline);
00154 funcargtypes[0] = INTERNALOID;
00155 inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
00156 if (!OidIsValid(inlineOid))
00157 {
00158 inlineOid = ProcedureCreate(pltemplate->tmplinline,
00159 PG_CATALOG_NAMESPACE,
00160 false,
00161 false,
00162 VOIDOID,
00163 BOOTSTRAP_SUPERUSERID,
00164 ClanguageId,
00165 F_FMGR_C_VALIDATOR,
00166 pltemplate->tmplinline,
00167 pltemplate->tmpllibrary,
00168 false,
00169 false,
00170 false,
00171 false,
00172 true,
00173 PROVOLATILE_VOLATILE,
00174 buildoidvector(funcargtypes, 1),
00175 PointerGetDatum(NULL),
00176 PointerGetDatum(NULL),
00177 PointerGetDatum(NULL),
00178 NIL,
00179 PointerGetDatum(NULL),
00180 1,
00181 0);
00182 }
00183 }
00184 else
00185 inlineOid = InvalidOid;
00186
00187
00188
00189
00190
00191 if (pltemplate->tmplvalidator)
00192 {
00193 funcname = SystemFuncName(pltemplate->tmplvalidator);
00194 funcargtypes[0] = OIDOID;
00195 valOid = LookupFuncName(funcname, 1, funcargtypes, true);
00196 if (!OidIsValid(valOid))
00197 {
00198 valOid = ProcedureCreate(pltemplate->tmplvalidator,
00199 PG_CATALOG_NAMESPACE,
00200 false,
00201 false,
00202 VOIDOID,
00203 BOOTSTRAP_SUPERUSERID,
00204 ClanguageId,
00205 F_FMGR_C_VALIDATOR,
00206 pltemplate->tmplvalidator,
00207 pltemplate->tmpllibrary,
00208 false,
00209 false,
00210 false,
00211 false,
00212 true,
00213 PROVOLATILE_VOLATILE,
00214 buildoidvector(funcargtypes, 1),
00215 PointerGetDatum(NULL),
00216 PointerGetDatum(NULL),
00217 PointerGetDatum(NULL),
00218 NIL,
00219 PointerGetDatum(NULL),
00220 1,
00221 0);
00222 }
00223 }
00224 else
00225 valOid = InvalidOid;
00226
00227
00228 return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
00229 handlerOid, inlineOid,
00230 valOid, pltemplate->tmpltrusted);
00231 }
00232 else
00233 {
00234
00235
00236
00237
00238
00239 if (!stmt->plhandler)
00240 ereport(ERROR,
00241 (errcode(ERRCODE_UNDEFINED_OBJECT),
00242 errmsg("unsupported language \"%s\"",
00243 stmt->plname),
00244 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
00245
00246
00247
00248
00249 if (!superuser())
00250 ereport(ERROR,
00251 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00252 errmsg("must be superuser to create custom procedural language")));
00253
00254
00255
00256
00257
00258 handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false);
00259 funcrettype = get_func_rettype(handlerOid);
00260 if (funcrettype != LANGUAGE_HANDLEROID)
00261 {
00262
00263
00264
00265
00266
00267 if (funcrettype == OPAQUEOID)
00268 {
00269 ereport(WARNING,
00270 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00271 errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"",
00272 NameListToString(stmt->plhandler))));
00273 SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
00274 }
00275 else
00276 ereport(ERROR,
00277 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00278 errmsg("function %s must return type \"language_handler\"",
00279 NameListToString(stmt->plhandler))));
00280 }
00281
00282
00283 if (stmt->plinline)
00284 {
00285 funcargtypes[0] = INTERNALOID;
00286 inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
00287
00288 }
00289 else
00290 inlineOid = InvalidOid;
00291
00292
00293 if (stmt->plvalidator)
00294 {
00295 funcargtypes[0] = OIDOID;
00296 valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
00297
00298 }
00299 else
00300 valOid = InvalidOid;
00301
00302
00303 return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
00304 handlerOid, inlineOid,
00305 valOid, stmt->pltrusted);
00306 }
00307 }
00308
00309
00310
00311
00312 static Oid
00313 create_proc_lang(const char *languageName, bool replace,
00314 Oid languageOwner, Oid handlerOid, Oid inlineOid,
00315 Oid valOid, bool trusted)
00316 {
00317 Relation rel;
00318 TupleDesc tupDesc;
00319 Datum values[Natts_pg_language];
00320 bool nulls[Natts_pg_language];
00321 bool replaces[Natts_pg_language];
00322 NameData langname;
00323 HeapTuple oldtup;
00324 HeapTuple tup;
00325 bool is_update;
00326 ObjectAddress myself,
00327 referenced;
00328
00329 rel = heap_open(LanguageRelationId, RowExclusiveLock);
00330 tupDesc = RelationGetDescr(rel);
00331
00332
00333 memset(values, 0, sizeof(values));
00334 memset(nulls, false, sizeof(nulls));
00335 memset(replaces, true, sizeof(replaces));
00336
00337 namestrcpy(&langname, languageName);
00338 values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
00339 values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
00340 values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
00341 values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
00342 values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
00343 values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
00344 values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
00345 nulls[Anum_pg_language_lanacl - 1] = true;
00346
00347
00348 oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
00349
00350 if (HeapTupleIsValid(oldtup))
00351 {
00352
00353 if (!replace)
00354 ereport(ERROR,
00355 (errcode(ERRCODE_DUPLICATE_OBJECT),
00356 errmsg("language \"%s\" already exists", languageName)));
00357 if (!pg_language_ownercheck(HeapTupleGetOid(oldtup), languageOwner))
00358 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
00359 languageName);
00360
00361
00362
00363
00364
00365 replaces[Anum_pg_language_lanowner - 1] = false;
00366 replaces[Anum_pg_language_lanacl - 1] = false;
00367
00368
00369 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
00370 simple_heap_update(rel, &tup->t_self, tup);
00371
00372 ReleaseSysCache(oldtup);
00373 is_update = true;
00374 }
00375 else
00376 {
00377
00378 tup = heap_form_tuple(tupDesc, values, nulls);
00379 simple_heap_insert(rel, tup);
00380 is_update = false;
00381 }
00382
00383
00384 CatalogUpdateIndexes(rel, tup);
00385
00386
00387
00388
00389
00390
00391
00392 myself.classId = LanguageRelationId;
00393 myself.objectId = HeapTupleGetOid(tup);
00394 myself.objectSubId = 0;
00395
00396 if (is_update)
00397 deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
00398
00399
00400 if (!is_update)
00401 recordDependencyOnOwner(myself.classId, myself.objectId,
00402 languageOwner);
00403
00404
00405 recordDependencyOnCurrentExtension(&myself, is_update);
00406
00407
00408 referenced.classId = ProcedureRelationId;
00409 referenced.objectId = handlerOid;
00410 referenced.objectSubId = 0;
00411 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00412
00413
00414 if (OidIsValid(inlineOid))
00415 {
00416 referenced.classId = ProcedureRelationId;
00417 referenced.objectId = inlineOid;
00418 referenced.objectSubId = 0;
00419 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00420 }
00421
00422
00423 if (OidIsValid(valOid))
00424 {
00425 referenced.classId = ProcedureRelationId;
00426 referenced.objectId = valOid;
00427 referenced.objectSubId = 0;
00428 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00429 }
00430
00431
00432 InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
00433
00434 heap_close(rel, RowExclusiveLock);
00435
00436 return myself.objectId;
00437 }
00438
00439
00440
00441
00442 static PLTemplate *
00443 find_language_template(const char *languageName)
00444 {
00445 PLTemplate *result;
00446 Relation rel;
00447 SysScanDesc scan;
00448 ScanKeyData key;
00449 HeapTuple tup;
00450
00451 rel = heap_open(PLTemplateRelationId, AccessShareLock);
00452
00453 ScanKeyInit(&key,
00454 Anum_pg_pltemplate_tmplname,
00455 BTEqualStrategyNumber, F_NAMEEQ,
00456 NameGetDatum(languageName));
00457 scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
00458 SnapshotNow, 1, &key);
00459
00460 tup = systable_getnext(scan);
00461 if (HeapTupleIsValid(tup))
00462 {
00463 Form_pg_pltemplate tmpl = (Form_pg_pltemplate) GETSTRUCT(tup);
00464 Datum datum;
00465 bool isnull;
00466
00467 result = (PLTemplate *) palloc0(sizeof(PLTemplate));
00468 result->tmpltrusted = tmpl->tmpltrusted;
00469 result->tmpldbacreate = tmpl->tmpldbacreate;
00470
00471
00472 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
00473 RelationGetDescr(rel), &isnull);
00474 if (!isnull)
00475 result->tmplhandler = TextDatumGetCString(datum);
00476
00477 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplinline,
00478 RelationGetDescr(rel), &isnull);
00479 if (!isnull)
00480 result->tmplinline = TextDatumGetCString(datum);
00481
00482 datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
00483 RelationGetDescr(rel), &isnull);
00484 if (!isnull)
00485 result->tmplvalidator = TextDatumGetCString(datum);
00486
00487 datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary,
00488 RelationGetDescr(rel), &isnull);
00489 if (!isnull)
00490 result->tmpllibrary = TextDatumGetCString(datum);
00491
00492
00493 if (!result->tmplhandler || !result->tmpllibrary)
00494 result = NULL;
00495 }
00496 else
00497 result = NULL;
00498
00499 systable_endscan(scan);
00500
00501 heap_close(rel, AccessShareLock);
00502
00503 return result;
00504 }
00505
00506
00507
00508
00509
00510 bool
00511 PLTemplateExists(const char *languageName)
00512 {
00513 return (find_language_template(languageName) != NULL);
00514 }
00515
00516
00517
00518
00519 void
00520 DropProceduralLanguageById(Oid langOid)
00521 {
00522 Relation rel;
00523 HeapTuple langTup;
00524
00525 rel = heap_open(LanguageRelationId, RowExclusiveLock);
00526
00527 langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(langOid));
00528 if (!HeapTupleIsValid(langTup))
00529 elog(ERROR, "cache lookup failed for language %u", langOid);
00530
00531 simple_heap_delete(rel, &langTup->t_self);
00532
00533 ReleaseSysCache(langTup);
00534
00535 heap_close(rel, RowExclusiveLock);
00536 }
00537
00538
00539
00540
00541
00542
00543
00544 Oid
00545 get_language_oid(const char *langname, bool missing_ok)
00546 {
00547 Oid oid;
00548
00549 oid = GetSysCacheOid1(LANGNAME, CStringGetDatum(langname));
00550 if (!OidIsValid(oid) && !missing_ok)
00551 ereport(ERROR,
00552 (errcode(ERRCODE_UNDEFINED_OBJECT),
00553 errmsg("language \"%s\" does not exist", langname)));
00554 return oid;
00555 }