1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_proc relation
6 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.115 2004/04/02 23:14:05 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "catalog/catname.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_language.h"
22 #include "catalog/pg_proc.h"
23 #include "executor/executor.h"
25 #include "miscadmin.h"
26 #include "mb/pg_wchar.h"
27 #include "parser/parse_coerce.h"
28 #include "parser/parse_expr.h"
29 #include "parser/parse_type.h"
30 #include "tcop/pquery.h"
31 #include "tcop/tcopprot.h"
32 #include "utils/acl.h"
33 #include "utils/builtins.h"
34 #include "utils/lsyscache.h"
35 #include "utils/syscache.h"
39 bool check_function_bodies = true;
42 Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
43 Datum fmgr_c_validator(PG_FUNCTION_ARGS);
44 Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
46 static Datum create_parameternames_array(int parameterCount,
47 const char *parameterNames[]);
48 static void sql_function_parse_error_callback(void *arg);
49 static int match_prosrc_to_query(const char *prosrc, const char *queryText,
51 static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
52 int cursorpos, int *newcursorpos);
55 /* ----------------------------------------------------------------
57 * ----------------------------------------------------------------
60 ProcedureCreate(const char *procedureName,
66 Oid languageValidator,
70 bool security_definer,
74 const Oid *parameterTypes,
75 const char *parameterNames[])
81 char nulls[Natts_pg_proc];
82 Datum values[Natts_pg_proc];
83 char replaces[Natts_pg_proc];
84 Oid typev[FUNC_MAX_ARGS];
97 Assert(PointerIsValid(prosrc));
98 Assert(PointerIsValid(probin));
100 if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
102 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
103 errmsg("functions cannot have more than %d arguments",
107 * Do not allow return type ANYARRAY or ANYELEMENT unless at least one
108 * argument is also ANYARRAY or ANYELEMENT
110 if (returnType == ANYARRAYOID || returnType == ANYELEMENTOID)
112 bool genericParam = false;
114 for (i = 0; i < parameterCount; i++)
116 if (parameterTypes[i] == ANYARRAYOID ||
117 parameterTypes[i] == ANYELEMENTOID)
126 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
127 errmsg("cannot determine result data type"),
128 errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
131 /* Make sure we have a zero-padded param type array */
132 MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
133 if (parameterCount > 0)
134 memcpy(typev, parameterTypes, parameterCount * sizeof(Oid));
136 /* Process param names, if given */
137 namesarray = create_parameternames_array(parameterCount, parameterNames);
140 * don't allow functions of complex types that have the same name as
141 * existing attributes of the type
143 if (parameterCount == 1 && OidIsValid(typev[0]) &&
144 (relid = typeidTypeRelid(typev[0])) != InvalidOid &&
145 get_attnum(relid, (char *) procedureName) != InvalidAttrNumber)
147 (errcode(ERRCODE_DUPLICATE_COLUMN),
148 errmsg("\"%s\" is already an attribute of type %s",
149 procedureName, format_type_be(typev[0]))));
152 * All seems OK; prepare the data to be inserted into pg_proc.
155 for (i = 0; i < Natts_pg_proc; ++i)
158 values[i] = (Datum) NULL;
163 namestrcpy(&procname, procedureName);
164 values[i++] = NameGetDatum(&procname); /* proname */
165 values[i++] = ObjectIdGetDatum(procNamespace); /* pronamespace */
166 values[i++] = Int32GetDatum(GetUserId()); /* proowner */
167 values[i++] = ObjectIdGetDatum(languageObjectId); /* prolang */
168 values[i++] = BoolGetDatum(isAgg); /* proisagg */
169 values[i++] = BoolGetDatum(security_definer); /* prosecdef */
170 values[i++] = BoolGetDatum(isStrict); /* proisstrict */
171 values[i++] = BoolGetDatum(returnsSet); /* proretset */
172 values[i++] = CharGetDatum(volatility); /* provolatile */
173 values[i++] = UInt16GetDatum(parameterCount); /* pronargs */
174 values[i++] = ObjectIdGetDatum(returnType); /* prorettype */
175 values[i++] = PointerGetDatum(typev); /* proargtypes */
176 values[i++] = namesarray; /* proargnames */
177 if (namesarray == PointerGetDatum(NULL))
178 nulls[Anum_pg_proc_proargnames - 1] = 'n';
179 values[i++] = DirectFunctionCall1(textin, /* prosrc */
180 CStringGetDatum(prosrc));
181 values[i++] = DirectFunctionCall1(textin, /* probin */
182 CStringGetDatum(probin));
183 /* proacl will be handled below */
185 rel = heap_openr(ProcedureRelationName, RowExclusiveLock);
186 tupDesc = rel->rd_att;
188 /* Check for pre-existing definition */
189 oldtup = SearchSysCache(PROCNAMENSP,
190 PointerGetDatum(procedureName),
191 UInt16GetDatum(parameterCount),
192 PointerGetDatum(typev),
193 ObjectIdGetDatum(procNamespace));
195 if (HeapTupleIsValid(oldtup))
197 /* There is one; okay to replace it? */
198 Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
202 (errcode(ERRCODE_DUPLICATE_FUNCTION),
203 errmsg("function \"%s\" already exists with same argument types",
205 if (GetUserId() != oldproc->proowner && !superuser())
206 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
210 * Not okay to change the return type of the existing proc, since
211 * existing rules, views, etc may depend on the return type.
213 if (returnType != oldproc->prorettype ||
214 returnsSet != oldproc->proretset)
216 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
217 errmsg("cannot change return type of existing function"),
218 errhint("Use DROP FUNCTION first.")));
220 /* Can't change aggregate status, either */
221 if (oldproc->proisagg != isAgg)
223 if (oldproc->proisagg)
225 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
226 errmsg("function \"%s\" is an aggregate",
230 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
231 errmsg("function \"%s\" is not an aggregate",
235 /* do not change existing ownership or permissions, either */
236 replaces[Anum_pg_proc_proowner - 1] = ' ';
237 replaces[Anum_pg_proc_proacl - 1] = ' ';
240 tup = heap_modifytuple(oldtup, rel, values, nulls, replaces);
241 simple_heap_update(rel, &tup->t_self, tup);
243 ReleaseSysCache(oldtup);
248 /* Creating a new procedure */
250 /* start out with empty permissions */
251 nulls[Anum_pg_proc_proacl - 1] = 'n';
253 tup = heap_formtuple(tupDesc, values, nulls);
254 simple_heap_insert(rel, tup);
258 /* Need to update indexes for either the insert or update case */
259 CatalogUpdateIndexes(rel, tup);
261 retval = HeapTupleGetOid(tup);
264 * Create dependencies for the new function. If we are updating an
265 * existing function, first delete any existing pg_depend entries.
268 deleteDependencyRecordsFor(RelOid_pg_proc, retval);
270 myself.classId = RelOid_pg_proc;
271 myself.objectId = retval;
272 myself.objectSubId = 0;
274 /* dependency on namespace */
275 referenced.classId = get_system_catalog_relid(NamespaceRelationName);
276 referenced.objectId = procNamespace;
277 referenced.objectSubId = 0;
278 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
280 /* dependency on implementation language */
281 referenced.classId = get_system_catalog_relid(LanguageRelationName);
282 referenced.objectId = languageObjectId;
283 referenced.objectSubId = 0;
284 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
286 /* dependency on return type */
287 referenced.classId = RelOid_pg_type;
288 referenced.objectId = returnType;
289 referenced.objectSubId = 0;
290 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
292 /* dependency on input types */
293 for (i = 0; i < parameterCount; i++)
295 referenced.classId = RelOid_pg_type;
296 referenced.objectId = typev[i];
297 referenced.objectSubId = 0;
298 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
303 heap_close(rel, RowExclusiveLock);
305 /* Verify function body */
306 if (OidIsValid(languageValidator))
308 /* Advance command counter so new tuple can be seen by validator */
309 CommandCounterIncrement();
310 OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
318 * create_parameternames_array - build proargnames value from an array
319 * of C strings. Returns a NULL pointer if no names provided.
322 create_parameternames_array(int parameterCount, const char *parameterNames[])
324 Datum elems[FUNC_MAX_ARGS];
330 return PointerGetDatum(NULL);
332 for (i=0; i<parameterCount; i++)
334 const char *s = parameterNames[i];
341 elems[i] = DirectFunctionCall1(textin, CStringGetDatum(s));
345 return PointerGetDatum(NULL);
347 names = construct_array(elems, parameterCount, TEXTOID, -1, false, 'i');
349 return PointerGetDatum(names);
354 * check_sql_fn_retval() -- check return value of a list of sql parse trees.
356 * The return value of a sql function is the value returned by
357 * the final query in the function. We do some ad-hoc type checking here
358 * to be sure that the user is returning the type he claims.
360 * This is normally applied during function definition, but in the case
361 * of a function with polymorphic arguments, we instead apply it during
362 * function execution startup. The rettype is then the actual resolved
363 * output type of the function, rather than the declared type. (Therefore,
364 * we should never see ANYARRAY or ANYELEMENT as rettype.)
366 * The return value is true if the function returns the entire tuple result
367 * of its final SELECT, and false otherwise. Note that because we allow
368 * "SELECT rowtype_expression", this may be false even when the declared
369 * function return type is a rowtype.
372 check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
382 int relnatts; /* physical number of columns in rel */
383 int rellogcols; /* # of nondeleted columns in rel */
384 int colindex; /* physical column index */
386 /* guard against empty function body; OK only if void return type */
387 if (queryTreeList == NIL)
389 if (rettype != VOIDOID)
391 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
392 errmsg("return type mismatch in function declared to return %s",
393 format_type_be(rettype)),
394 errdetail("Function's final statement must be a SELECT.")));
398 /* find the final query */
399 parse = (Query *) llast(queryTreeList);
401 cmd = parse->commandType;
402 tlist = parse->targetList;
405 * The last query must be a SELECT if and only if return type isn't
408 if (rettype == VOIDOID)
410 if (cmd == CMD_SELECT)
412 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
413 errmsg("return type mismatch in function declared to return %s",
414 format_type_be(rettype)),
415 errdetail("Function's final statement must not be a SELECT.")));
419 /* by here, the function is declared to return some type */
420 if (cmd != CMD_SELECT)
422 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
423 errmsg("return type mismatch in function declared to return %s",
424 format_type_be(rettype)),
425 errdetail("Function's final statement must be a SELECT.")));
428 * Count the non-junk entries in the result targetlist.
430 tlistlen = ExecCleanTargetListLength(tlist);
432 typerelid = typeidTypeRelid(rettype);
434 if (fn_typtype == 'b' || fn_typtype == 'd')
436 /* Shouldn't have a typerelid */
437 Assert(typerelid == InvalidOid);
440 * For base-type returns, the target list should have exactly one
441 * entry, and its type should agree with what the user declared.
442 * (As of Postgres 7.2, we accept binary-compatible types too.)
446 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
447 errmsg("return type mismatch in function declared to return %s",
448 format_type_be(rettype)),
449 errdetail("Final SELECT must return exactly one column.")));
451 restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
452 if (!IsBinaryCoercible(restype, rettype))
454 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
455 errmsg("return type mismatch in function declared to return %s",
456 format_type_be(rettype)),
457 errdetail("Actual return type is %s.",
458 format_type_be(restype))));
460 else if (fn_typtype == 'c')
462 /* Must have a typerelid */
463 Assert(typerelid != InvalidOid);
466 * If the target list is of length 1, and the type of the varnode
467 * in the target list matches the declared return type, this is
468 * okay. This can happen, for example, where the body of the
469 * function is 'SELECT func2()', where func2 has the same return
470 * type as the function that's calling it.
474 restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
475 if (IsBinaryCoercible(restype, rettype))
476 return false; /* NOT returning whole tuple */
480 * Otherwise verify that the targetlist matches the return tuple
481 * type. This part of the typechecking is a hack. We look up the
482 * relation that is the declared return type, and scan the
483 * non-deleted attributes to ensure that they match the datatypes
484 * of the non-resjunk columns.
486 reln = relation_open(typerelid, AccessShareLock);
487 relnatts = reln->rd_rel->relnatts;
488 rellogcols = 0; /* we'll count nondeleted cols as we go */
491 foreach(tlistitem, tlist)
493 TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);
494 Form_pg_attribute attr;
498 if (tle->resdom->resjunk)
504 if (colindex > relnatts)
506 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
507 errmsg("return type mismatch in function declared to return %s",
508 format_type_be(rettype)),
509 errdetail("Final SELECT returns too many columns.")));
510 attr = reln->rd_att->attrs[colindex - 1];
511 } while (attr->attisdropped);
514 tletype = exprType((Node *) tle->expr);
515 atttype = attr->atttypid;
516 if (!IsBinaryCoercible(tletype, atttype))
518 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
519 errmsg("return type mismatch in function declared to return %s",
520 format_type_be(rettype)),
521 errdetail("Final SELECT returns %s instead of %s at column %d.",
522 format_type_be(tletype),
523 format_type_be(atttype),
530 if (colindex > relnatts)
532 if (!reln->rd_att->attrs[colindex - 1]->attisdropped)
536 if (tlistlen != rellogcols)
538 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
539 errmsg("return type mismatch in function declared to return %s",
540 format_type_be(rettype)),
541 errdetail("Final SELECT returns too few columns.")));
543 relation_close(reln, AccessShareLock);
545 /* Report that we are returning entire tuple result */
548 else if (rettype == RECORDOID)
551 * If the target list is of length 1, and the type of the varnode
552 * in the target list matches the declared return type, this is
553 * okay. This can happen, for example, where the body of the
554 * function is 'SELECT func2()', where func2 has the same return
555 * type as the function that's calling it.
559 restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
560 if (IsBinaryCoercible(restype, rettype))
561 return false; /* NOT returning whole tuple */
565 * Otherwise assume we are returning the whole tuple. Crosschecking
566 * against what the caller expects will happen at runtime.
570 else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
572 /* This should already have been caught ... */
574 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
575 errmsg("cannot determine result data type"),
576 errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
580 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
581 errmsg("return type %s is not supported for SQL functions",
582 format_type_be(rettype))));
590 * Validator for internal functions
592 * Check that the given internal function name (the "prosrc" value) is
593 * a known builtin function.
596 fmgr_internal_validator(PG_FUNCTION_ARGS)
598 Oid funcoid = PG_GETARG_OID(0);
606 * We do not honor check_function_bodies since it's unlikely the
607 * function name will be found later if it isn't there now.
610 tuple = SearchSysCache(PROCOID,
611 ObjectIdGetDatum(funcoid),
613 if (!HeapTupleIsValid(tuple))
614 elog(ERROR, "cache lookup failed for function %u", funcoid);
615 proc = (Form_pg_proc) GETSTRUCT(tuple);
617 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
619 elog(ERROR, "null prosrc");
620 prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
622 if (fmgr_internal_function(prosrc) == InvalidOid)
624 (errcode(ERRCODE_UNDEFINED_FUNCTION),
625 errmsg("there is no built-in function named \"%s\"",
628 ReleaseSysCache(tuple);
636 * Validator for C language functions
638 * Make sure that the library file exists, is loadable, and contains
639 * the specified link symbol. Also check for a valid function
640 * information record.
643 fmgr_c_validator(PG_FUNCTION_ARGS)
645 Oid funcoid = PG_GETARG_OID(0);
655 * It'd be most consistent to skip the check if !check_function_bodies,
656 * but the purpose of that switch is to be helpful for pg_dump loading,
657 * and for pg_dump loading it's much better if we *do* check.
660 tuple = SearchSysCache(PROCOID,
661 ObjectIdGetDatum(funcoid),
663 if (!HeapTupleIsValid(tuple))
664 elog(ERROR, "cache lookup failed for function %u", funcoid);
665 proc = (Form_pg_proc) GETSTRUCT(tuple);
667 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
669 elog(ERROR, "null prosrc");
670 prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
672 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);
674 elog(ERROR, "null probin");
675 probin = DatumGetCString(DirectFunctionCall1(textout, tmp));
677 (void) load_external_function(probin, prosrc, true, &libraryhandle);
678 (void) fetch_finfo_record(libraryhandle, prosrc);
680 ReleaseSysCache(tuple);
687 * Validator for SQL language functions
689 * Parse it here in order to be sure that it contains no syntax errors.
692 fmgr_sql_validator(PG_FUNCTION_ARGS)
694 Oid funcoid = PG_GETARG_OID(0);
697 List *querytree_list;
701 ErrorContextCallback sqlerrcontext;
706 tuple = SearchSysCache(PROCOID,
707 ObjectIdGetDatum(funcoid),
709 if (!HeapTupleIsValid(tuple))
710 elog(ERROR, "cache lookup failed for function %u", funcoid);
711 proc = (Form_pg_proc) GETSTRUCT(tuple);
713 functyptype = get_typtype(proc->prorettype);
715 /* Disallow pseudotype result */
716 /* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
717 if (functyptype == 'p' &&
718 proc->prorettype != RECORDOID &&
719 proc->prorettype != VOIDOID &&
720 proc->prorettype != ANYARRAYOID &&
721 proc->prorettype != ANYELEMENTOID)
723 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
724 errmsg("SQL functions cannot return type %s",
725 format_type_be(proc->prorettype))));
727 /* Disallow pseudotypes in arguments */
728 /* except for ANYARRAY or ANYELEMENT */
730 for (i = 0; i < proc->pronargs; i++)
732 if (get_typtype(proc->proargtypes[i]) == 'p')
734 if (proc->proargtypes[i] == ANYARRAYOID ||
735 proc->proargtypes[i] == ANYELEMENTOID)
739 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
740 errmsg("SQL functions cannot have arguments of type %s",
741 format_type_be(proc->proargtypes[i]))));
745 /* Postpone body checks if !check_function_bodies */
746 if (check_function_bodies)
748 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
750 elog(ERROR, "null prosrc");
752 prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
755 * Setup error traceback support for ereport().
757 sqlerrcontext.callback = sql_function_parse_error_callback;
758 sqlerrcontext.arg = tuple;
759 sqlerrcontext.previous = error_context_stack;
760 error_context_stack = &sqlerrcontext;
763 * We can't do full prechecking of the function definition if there
764 * are any polymorphic input types, because actual datatypes of
765 * expression results will be unresolvable. The check will be done
766 * at runtime instead.
768 * We can run the text through the raw parser though; this will at
769 * least catch silly syntactic errors.
773 querytree_list = pg_parse_and_rewrite(prosrc,
776 (void) check_sql_fn_retval(proc->prorettype, functyptype,
780 querytree_list = pg_parse_query(prosrc);
782 error_context_stack = sqlerrcontext.previous;
785 ReleaseSysCache(tuple);
791 * Error context callback for handling errors in SQL function definitions
794 sql_function_parse_error_callback(void *arg)
796 HeapTuple tuple = (HeapTuple) arg;
797 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tuple);
802 /* See if it's a syntax error; if so, transpose to CREATE FUNCTION */
803 tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
805 elog(ERROR, "null prosrc");
806 prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
808 if (!function_parse_error_transpose(prosrc))
810 /* If it's not a syntax error, push info onto context stack */
811 errcontext("SQL function \"%s\"", NameStr(proc->proname));
818 * Adjust a syntax error occurring inside the function body of a CREATE
819 * FUNCTION command. This can be used by any function validator, not only
820 * for SQL-language functions. It is assumed that the syntax error position
821 * is initially relative to the function body string (as passed in). If
822 * possible, we adjust the position to reference the original CREATE command;
823 * if we can't manage that, we set up an "internal query" syntax error instead.
825 * Returns true if a syntax error was processed, false if not.
828 function_parse_error_transpose(const char *prosrc)
832 const char *queryText;
835 * Nothing to do unless we are dealing with a syntax error that has
838 * Some PLs may prefer to report the error position as an internal
839 * error to begin with, so check that too.
841 origerrposition = geterrposition();
842 if (origerrposition <= 0)
844 origerrposition = getinternalerrposition();
845 if (origerrposition <= 0)
849 /* We can get the original query text from the active portal (hack...) */
850 Assert(ActivePortal && ActivePortal->portalActive);
851 queryText = ActivePortal->sourceText;
853 /* Try to locate the prosrc in the original text */
854 newerrposition = match_prosrc_to_query(prosrc, queryText, origerrposition);
856 if (newerrposition > 0)
858 /* Successful, so fix error position to reference original query */
859 errposition(newerrposition);
860 /* Get rid of any report of the error as an "internal query" */
861 internalerrposition(0);
862 internalerrquery(NULL);
867 * If unsuccessful, convert the position to an internal position
868 * marker and give the function text as the internal query.
871 internalerrposition(origerrposition);
872 internalerrquery(prosrc);
879 * Try to locate the string literal containing the function body in the
880 * given text of the CREATE FUNCTION command. If successful, return the
881 * character (not byte) index within the command corresponding to the
882 * given character index within the literal. If not successful, return 0.
885 match_prosrc_to_query(const char *prosrc, const char *queryText,
889 * Rather than fully parsing the CREATE FUNCTION command, we just scan
890 * the command looking for $prosrc$ or 'prosrc'. This could be fooled
891 * (though not in any very probable scenarios), so fail if we find
892 * more than one match.
894 int prosrclen = strlen(prosrc);
895 int querylen = strlen(queryText);
900 for (curpos = 0; curpos < querylen-prosrclen; curpos++)
902 if (queryText[curpos] == '$' &&
903 strncmp(prosrc, &queryText[curpos+1], prosrclen) == 0 &&
904 queryText[curpos+1+prosrclen] == '$')
907 * Found a $foo$ match. Since there are no embedded quoting
908 * characters in a dollar-quoted literal, we don't have to do
909 * any fancy arithmetic; just offset by the starting position.
912 return 0; /* multiple matches, fail */
913 matchpos = pg_mbstrlen_with_len(queryText, curpos+1)
916 else if (queryText[curpos] == '\'' &&
917 match_prosrc_to_literal(prosrc, &queryText[curpos+1],
918 cursorpos, &newcursorpos))
921 * Found a 'foo' match. match_prosrc_to_literal() has adjusted
922 * for any quotes or backslashes embedded in the literal.
925 return 0; /* multiple matches, fail */
926 matchpos = pg_mbstrlen_with_len(queryText, curpos+1)
935 * Try to match the given source text to a single-quoted literal.
936 * If successful, adjust newcursorpos to correspond to the character
937 * (not byte) index corresponding to cursorpos in the source text.
939 * At entry, literal points just past a ' character. We must check for the
943 match_prosrc_to_literal(const char *prosrc, const char *literal,
944 int cursorpos, int *newcursorpos)
946 int newcp = cursorpos;
950 * This implementation handles backslashes and doubled quotes in the
951 * string literal. It does not handle the SQL syntax for literals
952 * continued across line boundaries.
954 * We do the comparison a character at a time, not a byte at a time,
955 * so that we can do the correct cursorpos math.
959 cursorpos--; /* characters left before cursor */
961 * Check for backslashes and doubled quotes in the literal; adjust
962 * newcp when one is found before the cursor.
964 if (*literal == '\\')
970 else if (*literal == '\'')
972 if (literal[1] != '\'')
978 chlen = pg_mblen(prosrc);
979 if (strncmp(prosrc, literal, chlen) != 0)
985 *newcursorpos = newcp;
987 if (*literal == '\'' && literal[1] != '\'')