00001
00002
00003
00004
00005
00006
00007 #include "postgres.h"
00008
00009 #include "access/htup_details.h"
00010 #include "access/transam.h"
00011 #include "funcapi.h"
00012 #include "catalog/pg_proc.h"
00013 #include "catalog/pg_type.h"
00014 #include "utils/builtins.h"
00015 #include "utils/hsearch.h"
00016 #include "utils/syscache.h"
00017
00018 #include "plpython.h"
00019
00020 #include "plpy_procedure.h"
00021
00022 #include "plpy_elog.h"
00023 #include "plpy_main.h"
00024
00025
00026 static HTAB *PLy_procedure_cache = NULL;
00027
00028 static PLyProcedure *PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger);
00029 static bool PLy_procedure_argument_valid(PLyTypeInfo *arg);
00030 static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup);
00031 static char *PLy_procedure_munge_source(const char *name, const char *src);
00032
00033
00034 void
00035 init_procedure_caches(void)
00036 {
00037 HASHCTL hash_ctl;
00038
00039 memset(&hash_ctl, 0, sizeof(hash_ctl));
00040 hash_ctl.keysize = sizeof(PLyProcedureKey);
00041 hash_ctl.entrysize = sizeof(PLyProcedureEntry);
00042 hash_ctl.hash = tag_hash;
00043 PLy_procedure_cache = hash_create("PL/Python procedures", 32, &hash_ctl,
00044 HASH_ELEM | HASH_FUNCTION);
00045 }
00046
00047
00048
00049
00050
00051
00052
00053
00054 char *
00055 PLy_procedure_name(PLyProcedure *proc)
00056 {
00057 if (proc == NULL)
00058 return "<unknown procedure>";
00059 return proc->proname;
00060 }
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 PLyProcedure *
00075 PLy_procedure_get(Oid fn_oid, Oid fn_rel, bool is_trigger)
00076 {
00077 bool use_cache = !(is_trigger && fn_rel == InvalidOid);
00078 HeapTuple procTup;
00079 PLyProcedureKey key;
00080 PLyProcedureEntry *volatile entry = NULL;
00081 PLyProcedure *volatile proc = NULL;
00082 bool found = false;
00083
00084 procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid));
00085 if (!HeapTupleIsValid(procTup))
00086 elog(ERROR, "cache lookup failed for function %u", fn_oid);
00087
00088
00089
00090
00091
00092
00093 if (use_cache)
00094 {
00095 key.fn_oid = fn_oid;
00096 key.fn_rel = fn_rel;
00097 entry = hash_search(PLy_procedure_cache, &key, HASH_ENTER, &found);
00098 proc = entry->proc;
00099 }
00100
00101 PG_TRY();
00102 {
00103 if (!found)
00104 {
00105
00106 proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
00107 if (use_cache)
00108 entry->proc = proc;
00109 }
00110 else if (!PLy_procedure_valid(proc, procTup))
00111 {
00112
00113 PLy_procedure_delete(proc);
00114 PLy_free(proc);
00115 proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
00116 entry->proc = proc;
00117 }
00118
00119 }
00120 PG_CATCH();
00121 {
00122
00123 if (use_cache)
00124 hash_search(PLy_procedure_cache, &key, HASH_REMOVE, NULL);
00125 PG_RE_THROW();
00126 }
00127 PG_END_TRY();
00128
00129 ReleaseSysCache(procTup);
00130
00131 return proc;
00132 }
00133
00134
00135
00136
00137 static PLyProcedure *
00138 PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
00139 {
00140 char procName[NAMEDATALEN + 256];
00141 Form_pg_proc procStruct;
00142 PLyProcedure *volatile proc;
00143 char *volatile procSource = NULL;
00144 Datum prosrcdatum;
00145 bool isnull;
00146 int i,
00147 rv;
00148
00149 procStruct = (Form_pg_proc) GETSTRUCT(procTup);
00150 rv = snprintf(procName, sizeof(procName),
00151 "__plpython_procedure_%s_%u",
00152 NameStr(procStruct->proname),
00153 fn_oid);
00154 if (rv >= sizeof(procName) || rv < 0)
00155 elog(ERROR, "procedure name would overrun buffer");
00156
00157 proc = PLy_malloc(sizeof(PLyProcedure));
00158 proc->proname = PLy_strdup(NameStr(procStruct->proname));
00159 proc->pyname = PLy_strdup(procName);
00160 proc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
00161 proc->fn_tid = procTup->t_self;
00162
00163 proc->fn_readonly =
00164 (procStruct->provolatile != PROVOLATILE_VOLATILE);
00165 PLy_typeinfo_init(&proc->result);
00166 for (i = 0; i < FUNC_MAX_ARGS; i++)
00167 PLy_typeinfo_init(&proc->args[i]);
00168 proc->nargs = 0;
00169 proc->code = proc->statics = NULL;
00170 proc->globals = NULL;
00171 proc->is_setof = procStruct->proretset;
00172 proc->setof = NULL;
00173 proc->src = NULL;
00174 proc->argnames = NULL;
00175
00176 PG_TRY();
00177 {
00178
00179
00180
00181
00182 if (!is_trigger)
00183 {
00184 HeapTuple rvTypeTup;
00185 Form_pg_type rvTypeStruct;
00186
00187 rvTypeTup = SearchSysCache1(TYPEOID,
00188 ObjectIdGetDatum(procStruct->prorettype));
00189 if (!HeapTupleIsValid(rvTypeTup))
00190 elog(ERROR, "cache lookup failed for type %u",
00191 procStruct->prorettype);
00192 rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
00193
00194
00195 if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
00196 {
00197 if (procStruct->prorettype == TRIGGEROID)
00198 ereport(ERROR,
00199 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00200 errmsg("trigger functions can only be called as triggers")));
00201 else if (procStruct->prorettype != VOIDOID &&
00202 procStruct->prorettype != RECORDOID)
00203 ereport(ERROR,
00204 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00205 errmsg("PL/Python functions cannot return type %s",
00206 format_type_be(procStruct->prorettype))));
00207 }
00208
00209 if (rvTypeStruct->typtype == TYPTYPE_COMPOSITE ||
00210 procStruct->prorettype == RECORDOID)
00211 {
00212
00213
00214
00215
00216 proc->result.out.d.typoid = procStruct->prorettype;
00217 proc->result.out.d.typmod = -1;
00218 proc->result.is_rowtype = 2;
00219 }
00220 else
00221 {
00222
00223 PLy_output_datum_func(&proc->result, rvTypeTup);
00224 }
00225
00226 ReleaseSysCache(rvTypeTup);
00227 }
00228
00229
00230
00231
00232
00233
00234
00235 if (procStruct->pronargs)
00236 {
00237 Oid *types;
00238 char **names,
00239 *modes;
00240 int i,
00241 pos,
00242 total;
00243
00244
00245 total = get_func_arg_info(procTup, &types, &names, &modes);
00246
00247
00248 if (modes == NULL)
00249 proc->nargs = total;
00250 else
00251 {
00252
00253 for (i = 0; i < total; i++)
00254 {
00255 if (modes[i] != PROARGMODE_OUT &&
00256 modes[i] != PROARGMODE_TABLE)
00257 (proc->nargs)++;
00258 }
00259 }
00260
00261 proc->argnames = (char **) PLy_malloc0(sizeof(char *) * proc->nargs);
00262 for (i = pos = 0; i < total; i++)
00263 {
00264 HeapTuple argTypeTup;
00265 Form_pg_type argTypeStruct;
00266
00267 if (modes &&
00268 (modes[i] == PROARGMODE_OUT ||
00269 modes[i] == PROARGMODE_TABLE))
00270 continue;
00271
00272 Assert(types[i] == procStruct->proargtypes.values[pos]);
00273
00274 argTypeTup = SearchSysCache1(TYPEOID,
00275 ObjectIdGetDatum(types[i]));
00276 if (!HeapTupleIsValid(argTypeTup))
00277 elog(ERROR, "cache lookup failed for type %u", types[i]);
00278 argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
00279
00280
00281 switch (argTypeStruct->typtype)
00282 {
00283 case TYPTYPE_PSEUDO:
00284
00285 ereport(ERROR,
00286 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00287 errmsg("PL/Python functions cannot accept type %s",
00288 format_type_be(types[i]))));
00289 break;
00290 case TYPTYPE_COMPOSITE:
00291
00292 proc->args[pos].is_rowtype = 2;
00293 break;
00294 default:
00295 PLy_input_datum_func(&(proc->args[pos]),
00296 types[i],
00297 argTypeTup);
00298 break;
00299 }
00300
00301
00302 proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL;
00303
00304 ReleaseSysCache(argTypeTup);
00305
00306 pos++;
00307 }
00308 }
00309
00310
00311
00312
00313 prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
00314 Anum_pg_proc_prosrc, &isnull);
00315 if (isnull)
00316 elog(ERROR, "null prosrc");
00317 procSource = TextDatumGetCString(prosrcdatum);
00318
00319 PLy_procedure_compile(proc, procSource);
00320
00321 pfree(procSource);
00322 procSource = NULL;
00323 }
00324 PG_CATCH();
00325 {
00326 PLy_procedure_delete(proc);
00327 if (procSource)
00328 pfree(procSource);
00329
00330 PG_RE_THROW();
00331 }
00332 PG_END_TRY();
00333
00334 return proc;
00335 }
00336
00337
00338
00339
00340 void
00341 PLy_procedure_compile(PLyProcedure *proc, const char *src)
00342 {
00343 PyObject *crv = NULL;
00344 char *msrc;
00345
00346 proc->globals = PyDict_Copy(PLy_interp_globals);
00347
00348
00349
00350
00351
00352 proc->statics = PyDict_New();
00353 PyDict_SetItemString(proc->globals, "SD", proc->statics);
00354
00355
00356
00357
00358 msrc = PLy_procedure_munge_source(proc->pyname, src);
00359
00360 proc->src = PLy_strdup(msrc);
00361 crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL);
00362 pfree(msrc);
00363
00364 if (crv != NULL)
00365 {
00366 int clen;
00367 char call[NAMEDATALEN + 256];
00368
00369 Py_DECREF(crv);
00370
00371
00372
00373
00374 clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
00375 if (clen < 0 || clen >= sizeof(call))
00376 elog(ERROR, "string would overflow buffer");
00377 proc->code = Py_CompileString(call, "<string>", Py_eval_input);
00378 if (proc->code != NULL)
00379 return;
00380 }
00381
00382 if (proc->proname)
00383 PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
00384 proc->proname);
00385 else
00386 PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
00387 }
00388
00389 void
00390 PLy_procedure_delete(PLyProcedure *proc)
00391 {
00392 int i;
00393
00394 Py_XDECREF(proc->code);
00395 Py_XDECREF(proc->statics);
00396 Py_XDECREF(proc->globals);
00397 if (proc->proname)
00398 PLy_free(proc->proname);
00399 if (proc->pyname)
00400 PLy_free(proc->pyname);
00401 for (i = 0; i < proc->nargs; i++)
00402 {
00403 if (proc->args[i].is_rowtype == 1)
00404 {
00405 if (proc->args[i].in.r.atts)
00406 PLy_free(proc->args[i].in.r.atts);
00407 if (proc->args[i].out.r.atts)
00408 PLy_free(proc->args[i].out.r.atts);
00409 }
00410 if (proc->argnames && proc->argnames[i])
00411 PLy_free(proc->argnames[i]);
00412 }
00413 if (proc->src)
00414 PLy_free(proc->src);
00415 if (proc->argnames)
00416 PLy_free(proc->argnames);
00417 }
00418
00419
00420
00421
00422 static bool
00423 PLy_procedure_argument_valid(PLyTypeInfo *arg)
00424 {
00425 HeapTuple relTup;
00426 bool valid;
00427
00428
00429 if (arg->is_rowtype != 1)
00430 return true;
00431
00432
00433
00434
00435
00436 if (!OidIsValid(arg->typ_relid))
00437 return true;
00438
00439
00440 Assert(TransactionIdIsValid(arg->typrel_xmin));
00441 Assert(ItemPointerIsValid(&arg->typrel_tid));
00442
00443
00444 relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid));
00445 if (!HeapTupleIsValid(relTup))
00446 elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid);
00447
00448
00449 valid = (arg->typrel_xmin == HeapTupleHeaderGetXmin(relTup->t_data) &&
00450 ItemPointerEquals(&arg->typrel_tid, &relTup->t_self));
00451
00452 ReleaseSysCache(relTup);
00453
00454 return valid;
00455 }
00456
00457
00458
00459
00460 static bool
00461 PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
00462 {
00463 int i;
00464 bool valid;
00465
00466 Assert(proc != NULL);
00467
00468
00469 if (!(proc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
00470 ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
00471 return false;
00472
00473
00474 valid = true;
00475 for (i = 0; i < proc->nargs; i++)
00476 {
00477 valid = PLy_procedure_argument_valid(&proc->args[i]);
00478
00479
00480 if (!valid)
00481 break;
00482 }
00483
00484
00485 if (valid)
00486 valid = PLy_procedure_argument_valid(&proc->result);
00487
00488 return valid;
00489 }
00490
00491 static char *
00492 PLy_procedure_munge_source(const char *name, const char *src)
00493 {
00494 char *mrc,
00495 *mp;
00496 const char *sp;
00497 size_t mlen,
00498 plen;
00499
00500
00501
00502
00503 mlen = (strlen(src) * 2) + strlen(name) + 16;
00504
00505 mrc = palloc(mlen);
00506 plen = snprintf(mrc, mlen, "def %s():\n\t", name);
00507 Assert(plen >= 0 && plen < mlen);
00508
00509 sp = src;
00510 mp = mrc + plen;
00511
00512 while (*sp != '\0')
00513 {
00514 if (*sp == '\r' && *(sp + 1) == '\n')
00515 sp++;
00516
00517 if (*sp == '\n' || *sp == '\r')
00518 {
00519 *mp++ = '\n';
00520 *mp++ = '\t';
00521 sp++;
00522 }
00523 else
00524 *mp++ = *sp++;
00525 }
00526 *mp++ = '\n';
00527 *mp++ = '\n';
00528 *mp = '\0';
00529
00530 if (mp > (mrc + mlen))
00531 elog(FATAL, "buffer overrun in PLy_munge_source");
00532
00533 return mrc;
00534 }