00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/htup_details.h"
00018 #include "access/xact.h"
00019 #include "catalog/dependency.h"
00020 #include "catalog/indexing.h"
00021 #include "catalog/objectaccess.h"
00022 #include "catalog/pg_language.h"
00023 #include "catalog/pg_namespace.h"
00024 #include "catalog/pg_proc.h"
00025 #include "catalog/pg_proc_fn.h"
00026 #include "catalog/pg_type.h"
00027 #include "executor/functions.h"
00028 #include "funcapi.h"
00029 #include "mb/pg_wchar.h"
00030 #include "miscadmin.h"
00031 #include "nodes/nodeFuncs.h"
00032 #include "parser/parse_type.h"
00033 #include "tcop/pquery.h"
00034 #include "tcop/tcopprot.h"
00035 #include "utils/acl.h"
00036 #include "utils/builtins.h"
00037 #include "utils/lsyscache.h"
00038 #include "utils/rel.h"
00039 #include "utils/syscache.h"
00040
00041
00042 Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
00043 Datum fmgr_c_validator(PG_FUNCTION_ARGS);
00044 Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
00045
00046 typedef struct
00047 {
00048 char *proname;
00049 char *prosrc;
00050 } parse_error_callback_arg;
00051
00052 static void sql_function_parse_error_callback(void *arg);
00053 static int match_prosrc_to_query(const char *prosrc, const char *queryText,
00054 int cursorpos);
00055 static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
00056 int cursorpos, int *newcursorpos);
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 Oid
00068 ProcedureCreate(const char *procedureName,
00069 Oid procNamespace,
00070 bool replace,
00071 bool returnsSet,
00072 Oid returnType,
00073 Oid proowner,
00074 Oid languageObjectId,
00075 Oid languageValidator,
00076 const char *prosrc,
00077 const char *probin,
00078 bool isAgg,
00079 bool isWindowFunc,
00080 bool security_definer,
00081 bool isLeakProof,
00082 bool isStrict,
00083 char volatility,
00084 oidvector *parameterTypes,
00085 Datum allParameterTypes,
00086 Datum parameterModes,
00087 Datum parameterNames,
00088 List *parameterDefaults,
00089 Datum proconfig,
00090 float4 procost,
00091 float4 prorows)
00092 {
00093 Oid retval;
00094 int parameterCount;
00095 int allParamCount;
00096 Oid *allParams;
00097 char *paramModes = NULL;
00098 bool genericInParam = false;
00099 bool genericOutParam = false;
00100 bool anyrangeInParam = false;
00101 bool anyrangeOutParam = false;
00102 bool internalInParam = false;
00103 bool internalOutParam = false;
00104 Oid variadicType = InvalidOid;
00105 Acl *proacl = NULL;
00106 Relation rel;
00107 HeapTuple tup;
00108 HeapTuple oldtup;
00109 bool nulls[Natts_pg_proc];
00110 Datum values[Natts_pg_proc];
00111 bool replaces[Natts_pg_proc];
00112 Oid relid;
00113 NameData procname;
00114 TupleDesc tupDesc;
00115 bool is_update;
00116 ObjectAddress myself,
00117 referenced;
00118 int i;
00119
00120
00121
00122
00123 Assert(PointerIsValid(prosrc));
00124
00125 parameterCount = parameterTypes->dim1;
00126 if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
00127 ereport(ERROR,
00128 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
00129 errmsg_plural("functions cannot have more than %d argument",
00130 "functions cannot have more than %d arguments",
00131 FUNC_MAX_ARGS,
00132 FUNC_MAX_ARGS)));
00133
00134
00135
00136 if (allParameterTypes != PointerGetDatum(NULL))
00137 {
00138
00139
00140
00141
00142
00143 ArrayType *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes);
00144
00145 allParamCount = ARR_DIMS(allParamArray)[0];
00146 if (ARR_NDIM(allParamArray) != 1 ||
00147 allParamCount <= 0 ||
00148 ARR_HASNULL(allParamArray) ||
00149 ARR_ELEMTYPE(allParamArray) != OIDOID)
00150 elog(ERROR, "allParameterTypes is not a 1-D Oid array");
00151 allParams = (Oid *) ARR_DATA_PTR(allParamArray);
00152 Assert(allParamCount >= parameterCount);
00153
00154 }
00155 else
00156 {
00157 allParamCount = parameterCount;
00158 allParams = parameterTypes->values;
00159 }
00160
00161 if (parameterModes != PointerGetDatum(NULL))
00162 {
00163
00164
00165
00166
00167
00168 ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes);
00169
00170 if (ARR_NDIM(modesArray) != 1 ||
00171 ARR_DIMS(modesArray)[0] != allParamCount ||
00172 ARR_HASNULL(modesArray) ||
00173 ARR_ELEMTYPE(modesArray) != CHAROID)
00174 elog(ERROR, "parameterModes is not a 1-D char array");
00175 paramModes = (char *) ARR_DATA_PTR(modesArray);
00176 }
00177
00178
00179
00180
00181
00182 for (i = 0; i < parameterCount; i++)
00183 {
00184 switch (parameterTypes->values[i])
00185 {
00186 case ANYARRAYOID:
00187 case ANYELEMENTOID:
00188 case ANYNONARRAYOID:
00189 case ANYENUMOID:
00190 genericInParam = true;
00191 break;
00192 case ANYRANGEOID:
00193 genericInParam = true;
00194 anyrangeInParam = true;
00195 break;
00196 case INTERNALOID:
00197 internalInParam = true;
00198 break;
00199 }
00200 }
00201
00202 if (allParameterTypes != PointerGetDatum(NULL))
00203 {
00204 for (i = 0; i < allParamCount; i++)
00205 {
00206 if (paramModes == NULL ||
00207 paramModes[i] == PROARGMODE_IN ||
00208 paramModes[i] == PROARGMODE_VARIADIC)
00209 continue;
00210
00211 switch (allParams[i])
00212 {
00213 case ANYARRAYOID:
00214 case ANYELEMENTOID:
00215 case ANYNONARRAYOID:
00216 case ANYENUMOID:
00217 genericOutParam = true;
00218 break;
00219 case ANYRANGEOID:
00220 genericOutParam = true;
00221 anyrangeOutParam = true;
00222 break;
00223 case INTERNALOID:
00224 internalOutParam = true;
00225 break;
00226 }
00227 }
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237 if ((IsPolymorphicType(returnType) || genericOutParam)
00238 && !genericInParam)
00239 ereport(ERROR,
00240 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00241 errmsg("cannot determine result data type"),
00242 errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
00243
00244 if ((returnType == ANYRANGEOID || anyrangeOutParam) &&
00245 !anyrangeInParam)
00246 ereport(ERROR,
00247 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00248 errmsg("cannot determine result data type"),
00249 errdetail("A function returning \"anyrange\" must have at least one \"anyrange\" argument.")));
00250
00251 if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
00252 ereport(ERROR,
00253 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00254 errmsg("unsafe use of pseudo-type \"internal\""),
00255 errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
00256
00257
00258
00259
00260
00261 if (parameterCount == 1 &&
00262 OidIsValid(parameterTypes->values[0]) &&
00263 (relid = typeidTypeRelid(parameterTypes->values[0])) != InvalidOid &&
00264 get_attnum(relid, procedureName) != InvalidAttrNumber)
00265 ereport(ERROR,
00266 (errcode(ERRCODE_DUPLICATE_COLUMN),
00267 errmsg("\"%s\" is already an attribute of type %s",
00268 procedureName,
00269 format_type_be(parameterTypes->values[0]))));
00270
00271 if (paramModes != NULL)
00272 {
00273
00274
00275
00276
00277
00278 for (i = 0; i < allParamCount; i++)
00279 {
00280 switch (paramModes[i])
00281 {
00282 case PROARGMODE_IN:
00283 case PROARGMODE_INOUT:
00284 if (OidIsValid(variadicType))
00285 elog(ERROR, "variadic parameter must be last");
00286 break;
00287 case PROARGMODE_OUT:
00288 case PROARGMODE_TABLE:
00289
00290 break;
00291 case PROARGMODE_VARIADIC:
00292 if (OidIsValid(variadicType))
00293 elog(ERROR, "variadic parameter must be last");
00294 switch (allParams[i])
00295 {
00296 case ANYOID:
00297 variadicType = ANYOID;
00298 break;
00299 case ANYARRAYOID:
00300 variadicType = ANYELEMENTOID;
00301 break;
00302 default:
00303 variadicType = get_element_type(allParams[i]);
00304 if (!OidIsValid(variadicType))
00305 elog(ERROR, "variadic parameter is not an array");
00306 break;
00307 }
00308 break;
00309 default:
00310 elog(ERROR, "invalid parameter mode '%c'", paramModes[i]);
00311 break;
00312 }
00313 }
00314 }
00315
00316
00317
00318
00319
00320 for (i = 0; i < Natts_pg_proc; ++i)
00321 {
00322 nulls[i] = false;
00323 values[i] = (Datum) 0;
00324 replaces[i] = true;
00325 }
00326
00327 namestrcpy(&procname, procedureName);
00328 values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname);
00329 values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
00330 values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner);
00331 values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
00332 values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
00333 values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
00334 values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
00335 values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid);
00336 values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
00337 values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(isWindowFunc);
00338 values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
00339 values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
00340 values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
00341 values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
00342 values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
00343 values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount);
00344 values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults));
00345 values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
00346 values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
00347 if (allParameterTypes != PointerGetDatum(NULL))
00348 values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes;
00349 else
00350 nulls[Anum_pg_proc_proallargtypes - 1] = true;
00351 if (parameterModes != PointerGetDatum(NULL))
00352 values[Anum_pg_proc_proargmodes - 1] = parameterModes;
00353 else
00354 nulls[Anum_pg_proc_proargmodes - 1] = true;
00355 if (parameterNames != PointerGetDatum(NULL))
00356 values[Anum_pg_proc_proargnames - 1] = parameterNames;
00357 else
00358 nulls[Anum_pg_proc_proargnames - 1] = true;
00359 if (parameterDefaults != NIL)
00360 values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults));
00361 else
00362 nulls[Anum_pg_proc_proargdefaults - 1] = true;
00363 values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
00364 if (probin)
00365 values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);
00366 else
00367 nulls[Anum_pg_proc_probin - 1] = true;
00368 if (proconfig != PointerGetDatum(NULL))
00369 values[Anum_pg_proc_proconfig - 1] = proconfig;
00370 else
00371 nulls[Anum_pg_proc_proconfig - 1] = true;
00372
00373
00374 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
00375 tupDesc = RelationGetDescr(rel);
00376
00377
00378 oldtup = SearchSysCache3(PROCNAMEARGSNSP,
00379 PointerGetDatum(procedureName),
00380 PointerGetDatum(parameterTypes),
00381 ObjectIdGetDatum(procNamespace));
00382
00383 if (HeapTupleIsValid(oldtup))
00384 {
00385
00386 Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
00387 Datum proargnames;
00388 bool isnull;
00389
00390 if (!replace)
00391 ereport(ERROR,
00392 (errcode(ERRCODE_DUPLICATE_FUNCTION),
00393 errmsg("function \"%s\" already exists with same argument types",
00394 procedureName)));
00395 if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner))
00396 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00397 procedureName);
00398
00399
00400
00401
00402
00403 if (returnType != oldproc->prorettype ||
00404 returnsSet != oldproc->proretset)
00405 ereport(ERROR,
00406 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00407 errmsg("cannot change return type of existing function"),
00408 errhint("Use DROP FUNCTION %s first.",
00409 format_procedure(HeapTupleGetOid(oldtup)))));
00410
00411
00412
00413
00414
00415 if (returnType == RECORDOID)
00416 {
00417 TupleDesc olddesc;
00418 TupleDesc newdesc;
00419
00420 olddesc = build_function_result_tupdesc_t(oldtup);
00421 newdesc = build_function_result_tupdesc_d(allParameterTypes,
00422 parameterModes,
00423 parameterNames);
00424 if (olddesc == NULL && newdesc == NULL)
00425 ;
00426 else if (olddesc == NULL || newdesc == NULL ||
00427 !equalTupleDescs(olddesc, newdesc))
00428 ereport(ERROR,
00429 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00430 errmsg("cannot change return type of existing function"),
00431 errdetail("Row type defined by OUT parameters is different."),
00432 errhint("Use DROP FUNCTION %s first.",
00433 format_procedure(HeapTupleGetOid(oldtup)))));
00434 }
00435
00436
00437
00438
00439
00440
00441 proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
00442 Anum_pg_proc_proargnames,
00443 &isnull);
00444 if (!isnull)
00445 {
00446 Datum proargmodes;
00447 char **old_arg_names;
00448 char **new_arg_names;
00449 int n_old_arg_names;
00450 int n_new_arg_names;
00451 int j;
00452
00453 proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
00454 Anum_pg_proc_proargmodes,
00455 &isnull);
00456 if (isnull)
00457 proargmodes = PointerGetDatum(NULL);
00458
00459 n_old_arg_names = get_func_input_arg_names(proargnames,
00460 proargmodes,
00461 &old_arg_names);
00462 n_new_arg_names = get_func_input_arg_names(parameterNames,
00463 parameterModes,
00464 &new_arg_names);
00465 for (j = 0; j < n_old_arg_names; j++)
00466 {
00467 if (old_arg_names[j] == NULL)
00468 continue;
00469 if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
00470 strcmp(old_arg_names[j], new_arg_names[j]) != 0)
00471 ereport(ERROR,
00472 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00473 errmsg("cannot change name of input parameter \"%s\"",
00474 old_arg_names[j]),
00475 errhint("Use DROP FUNCTION %s first.",
00476 format_procedure(HeapTupleGetOid(oldtup)))));
00477 }
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 if (oldproc->pronargdefaults != 0)
00489 {
00490 Datum proargdefaults;
00491 List *oldDefaults;
00492 ListCell *oldlc;
00493 ListCell *newlc;
00494
00495 if (list_length(parameterDefaults) < oldproc->pronargdefaults)
00496 ereport(ERROR,
00497 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00498 errmsg("cannot remove parameter defaults from existing function"),
00499 errhint("Use DROP FUNCTION %s first.",
00500 format_procedure(HeapTupleGetOid(oldtup)))));
00501
00502 proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
00503 Anum_pg_proc_proargdefaults,
00504 &isnull);
00505 Assert(!isnull);
00506 oldDefaults = (List *) stringToNode(TextDatumGetCString(proargdefaults));
00507 Assert(IsA(oldDefaults, List));
00508 Assert(list_length(oldDefaults) == oldproc->pronargdefaults);
00509
00510
00511 newlc = list_head(parameterDefaults);
00512 for (i = list_length(parameterDefaults) - oldproc->pronargdefaults;
00513 i > 0;
00514 i--)
00515 newlc = lnext(newlc);
00516
00517 foreach(oldlc, oldDefaults)
00518 {
00519 Node *oldDef = (Node *) lfirst(oldlc);
00520 Node *newDef = (Node *) lfirst(newlc);
00521
00522 if (exprType(oldDef) != exprType(newDef))
00523 ereport(ERROR,
00524 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00525 errmsg("cannot change data type of existing parameter default value"),
00526 errhint("Use DROP FUNCTION %s first.",
00527 format_procedure(HeapTupleGetOid(oldtup)))));
00528 newlc = lnext(newlc);
00529 }
00530 }
00531
00532
00533 if (oldproc->proisagg != isAgg)
00534 {
00535 if (oldproc->proisagg)
00536 ereport(ERROR,
00537 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00538 errmsg("function \"%s\" is an aggregate function",
00539 procedureName)));
00540 else
00541 ereport(ERROR,
00542 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00543 errmsg("function \"%s\" is not an aggregate function",
00544 procedureName)));
00545 }
00546 if (oldproc->proiswindow != isWindowFunc)
00547 {
00548 if (oldproc->proiswindow)
00549 ereport(ERROR,
00550 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00551 errmsg("function \"%s\" is a window function",
00552 procedureName)));
00553 else
00554 ereport(ERROR,
00555 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00556 errmsg("function \"%s\" is not a window function",
00557 procedureName)));
00558 }
00559
00560
00561
00562
00563
00564 replaces[Anum_pg_proc_proowner - 1] = false;
00565 replaces[Anum_pg_proc_proacl - 1] = false;
00566
00567
00568 tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
00569 simple_heap_update(rel, &tup->t_self, tup);
00570
00571 ReleaseSysCache(oldtup);
00572 is_update = true;
00573 }
00574 else
00575 {
00576
00577
00578
00579 proacl = get_user_default_acl(ACL_OBJECT_FUNCTION, proowner,
00580 procNamespace);
00581 if (proacl != NULL)
00582 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(proacl);
00583 else
00584 nulls[Anum_pg_proc_proacl - 1] = true;
00585
00586 tup = heap_form_tuple(tupDesc, values, nulls);
00587 simple_heap_insert(rel, tup);
00588 is_update = false;
00589 }
00590
00591
00592 CatalogUpdateIndexes(rel, tup);
00593
00594 retval = HeapTupleGetOid(tup);
00595
00596
00597
00598
00599
00600
00601
00602 if (is_update)
00603 deleteDependencyRecordsFor(ProcedureRelationId, retval, true);
00604
00605 myself.classId = ProcedureRelationId;
00606 myself.objectId = retval;
00607 myself.objectSubId = 0;
00608
00609
00610 referenced.classId = NamespaceRelationId;
00611 referenced.objectId = procNamespace;
00612 referenced.objectSubId = 0;
00613 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00614
00615
00616 referenced.classId = LanguageRelationId;
00617 referenced.objectId = languageObjectId;
00618 referenced.objectSubId = 0;
00619 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00620
00621
00622 referenced.classId = TypeRelationId;
00623 referenced.objectId = returnType;
00624 referenced.objectSubId = 0;
00625 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00626
00627
00628 for (i = 0; i < allParamCount; i++)
00629 {
00630 referenced.classId = TypeRelationId;
00631 referenced.objectId = allParams[i];
00632 referenced.objectSubId = 0;
00633 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00634 }
00635
00636
00637 if (parameterDefaults)
00638 recordDependencyOnExpr(&myself, (Node *) parameterDefaults,
00639 NIL, DEPENDENCY_NORMAL);
00640
00641
00642 if (!is_update)
00643 recordDependencyOnOwner(ProcedureRelationId, retval, proowner);
00644
00645
00646 if (!is_update && proacl != NULL)
00647 {
00648 int nnewmembers;
00649 Oid *newmembers;
00650
00651 nnewmembers = aclmembers(proacl, &newmembers);
00652 updateAclDependencies(ProcedureRelationId, retval, 0,
00653 proowner,
00654 0, NULL,
00655 nnewmembers, newmembers);
00656 }
00657
00658
00659 recordDependencyOnCurrentExtension(&myself, is_update);
00660
00661 heap_freetuple(tup);
00662
00663
00664 InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
00665
00666 heap_close(rel, RowExclusiveLock);
00667
00668
00669 if (OidIsValid(languageValidator))
00670 {
00671 ArrayType *set_items;
00672 int save_nestlevel;
00673
00674
00675 CommandCounterIncrement();
00676
00677
00678 set_items = (ArrayType *) DatumGetPointer(proconfig);
00679 if (set_items)
00680 {
00681 save_nestlevel = NewGUCNestLevel();
00682 ProcessGUCArray(set_items,
00683 (superuser() ? PGC_SUSET : PGC_USERSET),
00684 PGC_S_SESSION,
00685 GUC_ACTION_SAVE);
00686 }
00687 else
00688 save_nestlevel = 0;
00689
00690 OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
00691
00692 if (set_items)
00693 AtEOXact_GUC(true, save_nestlevel);
00694 }
00695
00696 return retval;
00697 }
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 Datum
00708 fmgr_internal_validator(PG_FUNCTION_ARGS)
00709 {
00710 Oid funcoid = PG_GETARG_OID(0);
00711 HeapTuple tuple;
00712 bool isnull;
00713 Datum tmp;
00714 char *prosrc;
00715
00716
00717
00718
00719
00720
00721 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
00722 if (!HeapTupleIsValid(tuple))
00723 elog(ERROR, "cache lookup failed for function %u", funcoid);
00724
00725 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
00726 if (isnull)
00727 elog(ERROR, "null prosrc");
00728 prosrc = TextDatumGetCString(tmp);
00729
00730 if (fmgr_internal_function(prosrc) == InvalidOid)
00731 ereport(ERROR,
00732 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00733 errmsg("there is no built-in function named \"%s\"",
00734 prosrc)));
00735
00736 ReleaseSysCache(tuple);
00737
00738 PG_RETURN_VOID();
00739 }
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750 Datum
00751 fmgr_c_validator(PG_FUNCTION_ARGS)
00752 {
00753 Oid funcoid = PG_GETARG_OID(0);
00754 void *libraryhandle;
00755 HeapTuple tuple;
00756 bool isnull;
00757 Datum tmp;
00758 char *prosrc;
00759 char *probin;
00760
00761
00762
00763
00764
00765
00766
00767 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
00768 if (!HeapTupleIsValid(tuple))
00769 elog(ERROR, "cache lookup failed for function %u", funcoid);
00770
00771 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
00772 if (isnull)
00773 elog(ERROR, "null prosrc for C function %u", funcoid);
00774 prosrc = TextDatumGetCString(tmp);
00775
00776 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);
00777 if (isnull)
00778 elog(ERROR, "null probin for C function %u", funcoid);
00779 probin = TextDatumGetCString(tmp);
00780
00781 (void) load_external_function(probin, prosrc, true, &libraryhandle);
00782 (void) fetch_finfo_record(libraryhandle, prosrc);
00783
00784 ReleaseSysCache(tuple);
00785
00786 PG_RETURN_VOID();
00787 }
00788
00789
00790
00791
00792
00793
00794
00795 Datum
00796 fmgr_sql_validator(PG_FUNCTION_ARGS)
00797 {
00798 Oid funcoid = PG_GETARG_OID(0);
00799 HeapTuple tuple;
00800 Form_pg_proc proc;
00801 List *raw_parsetree_list;
00802 List *querytree_list;
00803 ListCell *lc;
00804 bool isnull;
00805 Datum tmp;
00806 char *prosrc;
00807 parse_error_callback_arg callback_arg;
00808 ErrorContextCallback sqlerrcontext;
00809 bool haspolyarg;
00810 int i;
00811
00812 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
00813 if (!HeapTupleIsValid(tuple))
00814 elog(ERROR, "cache lookup failed for function %u", funcoid);
00815 proc = (Form_pg_proc) GETSTRUCT(tuple);
00816
00817
00818
00819 if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
00820 proc->prorettype != RECORDOID &&
00821 proc->prorettype != VOIDOID &&
00822 !IsPolymorphicType(proc->prorettype))
00823 ereport(ERROR,
00824 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00825 errmsg("SQL functions cannot return type %s",
00826 format_type_be(proc->prorettype))));
00827
00828
00829
00830 haspolyarg = false;
00831 for (i = 0; i < proc->pronargs; i++)
00832 {
00833 if (get_typtype(proc->proargtypes.values[i]) == TYPTYPE_PSEUDO)
00834 {
00835 if (IsPolymorphicType(proc->proargtypes.values[i]))
00836 haspolyarg = true;
00837 else
00838 ereport(ERROR,
00839 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00840 errmsg("SQL functions cannot have arguments of type %s",
00841 format_type_be(proc->proargtypes.values[i]))));
00842 }
00843 }
00844
00845
00846 if (check_function_bodies)
00847 {
00848 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
00849 if (isnull)
00850 elog(ERROR, "null prosrc");
00851
00852 prosrc = TextDatumGetCString(tmp);
00853
00854
00855
00856
00857 callback_arg.proname = NameStr(proc->proname);
00858 callback_arg.prosrc = prosrc;
00859
00860 sqlerrcontext.callback = sql_function_parse_error_callback;
00861 sqlerrcontext.arg = (void *) &callback_arg;
00862 sqlerrcontext.previous = error_context_stack;
00863 error_context_stack = &sqlerrcontext;
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874 raw_parsetree_list = pg_parse_query(prosrc);
00875
00876 if (!haspolyarg)
00877 {
00878
00879
00880
00881
00882 SQLFunctionParseInfoPtr pinfo;
00883
00884
00885 pinfo = prepare_sql_fn_parse_info(tuple, NULL, InvalidOid);
00886
00887 querytree_list = NIL;
00888 foreach(lc, raw_parsetree_list)
00889 {
00890 Node *parsetree = (Node *) lfirst(lc);
00891 List *querytree_sublist;
00892
00893 querytree_sublist = pg_analyze_and_rewrite_params(parsetree,
00894 prosrc,
00895 (ParserSetupHook) sql_fn_parser_setup,
00896 pinfo);
00897 querytree_list = list_concat(querytree_list,
00898 querytree_sublist);
00899 }
00900
00901 (void) check_sql_fn_retval(funcoid, proc->prorettype,
00902 querytree_list,
00903 NULL, NULL);
00904 }
00905
00906 error_context_stack = sqlerrcontext.previous;
00907 }
00908
00909 ReleaseSysCache(tuple);
00910
00911 PG_RETURN_VOID();
00912 }
00913
00914
00915
00916
00917 static void
00918 sql_function_parse_error_callback(void *arg)
00919 {
00920 parse_error_callback_arg *callback_arg = (parse_error_callback_arg *) arg;
00921
00922
00923 if (!function_parse_error_transpose(callback_arg->prosrc))
00924 {
00925
00926 errcontext("SQL function \"%s\"", callback_arg->proname);
00927 }
00928 }
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941 bool
00942 function_parse_error_transpose(const char *prosrc)
00943 {
00944 int origerrposition;
00945 int newerrposition;
00946 const char *queryText;
00947
00948
00949
00950
00951
00952
00953
00954
00955 origerrposition = geterrposition();
00956 if (origerrposition <= 0)
00957 {
00958 origerrposition = getinternalerrposition();
00959 if (origerrposition <= 0)
00960 return false;
00961 }
00962
00963
00964 Assert(ActivePortal && ActivePortal->status == PORTAL_ACTIVE);
00965 queryText = ActivePortal->sourceText;
00966
00967
00968 newerrposition = match_prosrc_to_query(prosrc, queryText, origerrposition);
00969
00970 if (newerrposition > 0)
00971 {
00972
00973 errposition(newerrposition);
00974
00975 internalerrposition(0);
00976 internalerrquery(NULL);
00977 }
00978 else
00979 {
00980
00981
00982
00983
00984 errposition(0);
00985 internalerrposition(origerrposition);
00986 internalerrquery(prosrc);
00987 }
00988
00989 return true;
00990 }
00991
00992
00993
00994
00995
00996
00997
00998 static int
00999 match_prosrc_to_query(const char *prosrc, const char *queryText,
01000 int cursorpos)
01001 {
01002
01003
01004
01005
01006
01007
01008 int prosrclen = strlen(prosrc);
01009 int querylen = strlen(queryText);
01010 int matchpos = 0;
01011 int curpos;
01012 int newcursorpos;
01013
01014 for (curpos = 0; curpos < querylen - prosrclen; curpos++)
01015 {
01016 if (queryText[curpos] == '$' &&
01017 strncmp(prosrc, &queryText[curpos + 1], prosrclen) == 0 &&
01018 queryText[curpos + 1 + prosrclen] == '$')
01019 {
01020
01021
01022
01023
01024
01025 if (matchpos)
01026 return 0;
01027 matchpos = pg_mbstrlen_with_len(queryText, curpos + 1)
01028 + cursorpos;
01029 }
01030 else if (queryText[curpos] == '\'' &&
01031 match_prosrc_to_literal(prosrc, &queryText[curpos + 1],
01032 cursorpos, &newcursorpos))
01033 {
01034
01035
01036
01037
01038 if (matchpos)
01039 return 0;
01040 matchpos = pg_mbstrlen_with_len(queryText, curpos + 1)
01041 + newcursorpos;
01042 }
01043 }
01044
01045 return matchpos;
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056 static bool
01057 match_prosrc_to_literal(const char *prosrc, const char *literal,
01058 int cursorpos, int *newcursorpos)
01059 {
01060 int newcp = cursorpos;
01061 int chlen;
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 while (*prosrc)
01072 {
01073 cursorpos--;
01074
01075
01076
01077
01078
01079 if (*literal == '\\')
01080 {
01081 literal++;
01082 if (cursorpos > 0)
01083 newcp++;
01084 }
01085 else if (*literal == '\'')
01086 {
01087 if (literal[1] != '\'')
01088 goto fail;
01089 literal++;
01090 if (cursorpos > 0)
01091 newcp++;
01092 }
01093 chlen = pg_mblen(prosrc);
01094 if (strncmp(prosrc, literal, chlen) != 0)
01095 goto fail;
01096 prosrc += chlen;
01097 literal += chlen;
01098 }
01099
01100 if (*literal == '\'' && literal[1] != '\'')
01101 {
01102
01103 *newcursorpos = newcp;
01104 return true;
01105 }
01106
01107 fail:
01108
01109 *newcursorpos = newcp;
01110 return false;
01111 }