diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml index 84f4f5c958f..b22b9e4088f 100644 --- a/doc/src/sgml/ref/create_function.sgml +++ b/doc/src/sgml/ref/create_function.sgml @@ -1,5 +1,5 @@ @@ -25,8 +25,14 @@ Postgres documentation CREATE FUNCTION name ( [ ftype [, ...] ] ) RETURNS rtype - AS definition + AS definition LANGUAGE 'langname' + + +CREATE FUNCTION name ( [ ftype [, ...] ] ) + RETURNS rtype + AS obj_file , link_symbol + LANGUAGE 'c' @@ -83,6 +89,22 @@ CREATE FUNCTION name ( [ + + obj_file , link_symbol + + + This form of the AS clause is used for + dynamically-linked, C language functions when the function name in + the C language source code is not the same as the name of the SQL + function. The string obj_file is the name of the file + containing the dynamically loadable object, and link_symbol, is the object's link + symbol which is the same as the name of the function in the C + language source code. + + + langname @@ -165,10 +187,10 @@ CREATE Postgres allows function "overloading"; that is, the same name can be used for several different functions - so long as they have distinct argument types. This facility must be - used with caution for internal - and C-language functions, however. - + so long as they have distinct argument types. This facility must + be used with caution for internal and + C-language functions, however. + Two internal @@ -181,18 +203,15 @@ CREATE - For dynamically-loaded C functions, the SQL name of the function must - be the same as the C function name, because the AS clause is used to - give the path name of the object file containing the C code. In this - situation it is best not to try to overload SQL function names. It - might work to load a C function that has the same C name as an internal - function or another dynamically-loaded function --- or it might not. - On some platforms the dynamic loader may botch the load in interesting - ways if there is a conflict of C function names. So, even if it works - for you today, you might regret overloading names later when you try - to run the code somewhere else. + When overloading SQL functions with C-language functions, give + each C-language instance of the function a distinct name, and use + the alternative form of the AS clause in the + CREATE FUNCTION syntax to ensure that + overloaded SQL functions names are resolved to the correct + dynamically linked objects. + A C function cannot return a set of values. @@ -227,7 +246,6 @@ SELECT one() AS answer; is correct. It is intended for use in a CHECK contraint. - CREATE FUNCTION ean_checkdigit(bpchar, bpchar) RETURNS bool AS '/usr1/proj/bray/sql/funcs.so' LANGUAGE 'c'; @@ -238,8 +256,41 @@ CREATE TABLE product ( eancode char(6) CHECK (eancode ~ '[0-9]{6}'), CONSTRAINT ean CHECK (ean_checkdigit(eanprefix, eancode)) ); - + + + + This example creates a function that does type conversion between the + user defined type complex, and the internal type point. The + function is implemented by a dynamically loaded object that was + compiled from C source. For Postgres to + find a type conversion function automatically, the sql function has + to have the same name as the return type, and overloading is + unavoidable. The function name is overloaded by using the second + form of the AS clause in the SQL definition + + +CREATE FUNCTION point(complex) RETURNS point + AS '/home/bernie/pgsql/lib/complex.so', 'complex_to_point' + LANGUAGE 'c'; + + + The C decalaration of the function is: + + +Point * complex_to_point (Complex *z) +{ + Point *p; + + p = (Point *) palloc(sizeof(Point)); + p->x = z->x; + p->y = z->y; + + return p; +} + + + @@ -283,8 +334,7 @@ CREATE TABLE product ( SQL/PSM CREATE FUNCTION has the following syntax: CREATE FUNCTION name - ( [ [ IN | OUT | INOUT ] etereable>eable> type [, ...] ] ) + ( [ [ IN | OUT | INOUT ] type [, ...] ] ) RETURNS rtype LANGUAGE 'langname' ESPECIFIC routine diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index 036d029d818..879f6f66672 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -357,25 +357,43 @@ WARN::function declared to return type EMP does not retrieve (EMP.*) Compiled (C) Language Functions - Functions written in C can be defined to Postgres, which will dynamically - load them into its address space. The AS - clause gives the full path name of the object file that contains the - function. This file is loaded either using - load(l) - or automatically the first time the function is necessary for - execution. Repeated execution of a function will cause negligible - additional overhead, as the function will remain in a main memory - cache. + Functions written in C can be compiled into dynamically loadable + objects, and used to implement user-defined SQL functions. The + first time the user defined function is called inside the backend, + the dynamic loader loads the function's object code into memory, + and links the function with the running + Postgres executable. The SQL syntax + for the command links the SQL function + to the C source function in one of two ways. If the SQL function + has the same name as the C source function the first form of the + statement is used. The string argument in the AS clause is the + full pathname of the file that contains the dynamically loadable + compiled object. If the name of C function is different from the + name of the SQL function, then the second form is used. In this + form the AS clause takes two string arguments, the first is the + full pathname of the dynamically loadable object file, and the + second is the link symbol that the dynamic loader should search + for. This link symbol is just the function name in the C source + code. + + After it is used for the first time, a dynamically loaded, user + function is retained in memory, and future calls to the function + only incur the small overhead of a symbol table lookup. - The string which specifies the object file (the string in the AS clause) - should be the full path - of the object code file for the function, bracketed by quotation - marks. (Postgres will not compile a - function automatically; it must - be compiled before it is used in a CREATE FUNCTION - command. See below for additional information.) + The string which specifies the object file (the string in the AS + clause) should be the full path of the object + code file for the function, bracketed by quotation marks. If a + link symbol is used in the AS clause, the link symbol should also be + bracketed by single quotation marks, and should be exactly the + same as the name of function in the C source code. On UNIX systems + the command nm will print all of the link + symbols in a dynamically loadable object. + (Postgres will not compile a function + automatically; it must be compiled before it is used in a CREATE + FUNCTION command. See below for additional information.) @@ -960,10 +978,13 @@ memmove(destination->data, buffer, 40); Name Space Conflicts - As of Postgres v6.5, - CREATE FUNCTION can decouple a C language - function name from the name of the entry point. This is now the - preferred technique to accomplish function overloading. + As of Postgres v6.6, the alternative + form of the AS clause for the SQL CREATE + FUNCTION command described in + decouples the SQL function name from the function name in the C + source code. This is now the preferred technique to accomplish + function overloading. diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index c7dc7d3ad1c..509d5026d30 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.34 1999/07/17 20:16:52 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.35 1999/09/28 04:34:40 momjian Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -178,23 +178,45 @@ compute_full_attributes(const List *parameters, int32 *byte_pct_p, } +/* + * For a dynamically linked C language object, the form of the clause is + * + * AS [, ] + * + * In all other cases + * + * AS + * + */ static void -interpret_AS_clause(const char *languageName, const char *as, +interpret_AS_clause(const char *languageName, const List *as, char **prosrc_str_p, char **probin_str_p) { + Assert(as != NIL); if (strcmp(languageName, "C") == 0) { - /* For "C" language, store the given string in probin */ - *prosrc_str_p = "-"; - *probin_str_p = (char *) as; + + /* + * For "C" language, store the file name in probin and, when + * given, the link symbol name in prosrc. + */ + *probin_str_p = strVal(lfirst(as)); + if (lnext(as) == NULL) + *prosrc_str_p = "-"; + else + *prosrc_str_p = strVal(lsecond(as)); } else { - /* Everything else wants the given string in prosrc */ - *prosrc_str_p = (char *) as; + /* Everything else wants the given string in prosrc. */ + *prosrc_str_p = strVal(lfirst(as)); *probin_str_p = "-"; + + if (lnext(as) != NULL) + elog(ERROR, "CREATE FUNCTION: parse error in 'AS %s, %s'.", + strVal(lfirst(as)), strVal(lsecond(as))); } } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 32c46e05d1c..67d7ac00cd1 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.99 1999/09/23 17:02:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.100 1999/09/28 04:34:44 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -163,7 +163,7 @@ Oid param_type(int t); /* used in parse_expr.c */ %type stmtblock, stmtmulti, result, relation_name_list, OptTableElementList, OptInherit, definition, - opt_with, func_args, func_args_list, + opt_with, func_args, func_args_list, func_as, oper_argtypes, RuleActionList, RuleActionBlock, RuleActionMulti, opt_column_list, columnList, opt_va_list, va_list, sort_clause, sortby_list, index_params, index_list, name_list, @@ -1923,7 +1923,7 @@ RecipeStmt: EXECUTE RECIPE recipe_name *****************************************************************************/ ProcedureStmt: CREATE FUNCTION func_name func_args - RETURNS func_return opt_with AS Sconst LANGUAGE Sconst + RETURNS func_return opt_with AS func_as LANGUAGE Sconst { ProcedureStmt *n = makeNode(ProcedureStmt); n->funcname = $3; @@ -1949,6 +1949,12 @@ func_args_list: TypeId { $$ = lappend($1,makeString($3)); } ; +func_as: Sconst + { $$ = lcons(makeString($1),NIL); } + | Sconst ',' Sconst + { $$ = lappend(lcons(makeString($1),NIL), makeString($3)); } + ; + func_return: set_opt TypeId { TypeName *n = makeNode(TypeName); diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index dcf2814171b..171f269127d 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.32 1999/09/18 19:08:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.33 1999/09/28 04:34:46 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -42,8 +42,11 @@ fmgr_dynamic(Oid procedureId, int *pronargs) HeapTuple procedureTuple; Form_pg_proc procedureStruct; char *proname, - *probinstring; + *probinstring, + *prosrcstring, + *linksymbol; Datum probinattr; + Datum prosrcattr; func_ptr user_fn; Relation rel; bool isnull; @@ -90,7 +93,32 @@ fmgr_dynamic(Oid procedureId, int *pronargs) heap_close(rel, AccessShareLock); - user_fn = handle_load(probinstring, proname); + prosrcattr = heap_getattr(procedureTuple, + Anum_pg_proc_prosrc, + RelationGetDescr(rel), &isnull); + + if (isnull) + { /* Use the proname for the link symbol */ + linksymbol = proname; + } + else if (!PointerIsValid(prosrcattr)) + { /* pg_proc must be messed up! */ + heap_close(rel); + elog(ERROR, "fmgr: Could not extract prosrc for %u from %s", + procedureId, ProcedureRelationName); + return (func_ptr) NULL; + } + else + { /* The text in prosrcattr is either "-" or + * a link symbol */ + prosrcstring = textout((struct varlena *) prosrcattr); + if (strcmp(prosrcstring, "-") == 0) + linksymbol = proname; + else + linksymbol = prosrcstring; + } + + user_fn = handle_load(probinstring, linksymbol); pfree(probinstring); diff --git a/src/bin/psql/psqlHelp.h b/src/bin/psql/psqlHelp.h index 020d8e450e1..63268c2cbd9 100644 --- a/src/bin/psql/psqlHelp.h +++ b/src/bin/psql/psqlHelp.h @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: psqlHelp.h,v 1.75 1999/09/27 20:27:20 momjian Exp $ + * $Id: psqlHelp.h,v 1.76 1999/09/28 04:34:48 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -88,8 +88,14 @@ static struct _helpStruct QL_HELP[] = { "create a user-defined function", "\ \tCREATE FUNCTION function_name ([type1, ...typeN]) RETURNS return_type\n\ -\tAS 'object_filename'|'sql-queries'|'builtin_function_name'\n\ -\tLANGUAGE 'c'|'sql'|'internal';"}, +\tAS 'sql-queries'|'builtin_function_name'|'object_filename'\n\ +\tLANGUAGE 'sql'|'internal'|'c';\n\ +\n\ +OR\n\ +\n\ +\tCREATE FUNCTION function_name ([type1, ...typeN]) RETURNS return_type\n\ +\tAS 'object_filename', 'link_symbol'\n\ +\tLANGUAGE 'c';"}, {"create index", "construct an index", "\ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 66c5a9132aa..4bf879137ac 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.79 1999/09/23 17:03:22 momjian Exp $ + * $Id: parsenodes.h,v 1.80 1999/09/28 04:34:50 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -70,7 +70,7 @@ typedef struct Query /* internal to planner */ List *base_rel_list; /* list of base-relation RelOptInfos */ List *join_rel_list; /* list of join-relation RelOptInfos */ - List *query_pathkeys; /* pathkeys for query_planner()'s result */ + List *query_pathkeys; /* pathkeys for query_planner()'s result */ } Query; @@ -361,7 +361,7 @@ typedef struct ProcedureStmt Node *returnType; /* the return type (as a string or a * TypeName (ie.setof) */ List *withClause; /* a list of ParamString */ - char *as; /* the SQL statement or filename */ + List *as; /* the SQL statement or filename */ char *language; /* C or SQL */ } ProcedureStmt; @@ -836,8 +836,10 @@ typedef struct ResTarget { NodeTag type; char *name; /* column name or NULL */ - List *indirection; /* subscripts for destination column, or NIL */ - Node *val; /* the value expression to compute or assign */ + List *indirection; /* subscripts for destination column, or + * NIL */ + Node *val; /* the value expression to compute or + * assign */ } ResTarget; /* @@ -970,7 +972,7 @@ typedef struct RangeTblEntry typedef struct SortClause { NodeTag type; - Index tleSortGroupRef; /* reference into targetlist */ + Index tleSortGroupRef;/* reference into targetlist */ Oid sortop; /* the sort operator to use */ } SortClause; diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 6151a6328d8..9ba3daacb64 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -799,7 +799,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim %type opt_analyze opt_va_list va_list ExplainStmt index_params %type index_list func_index index_elem opt_type opt_class access_method_clause %type index_opt_unique IndexStmt set_opt func_return def_rest -%type func_args_list func_args opt_with ProcedureStmt def_arg +%type func_as func_args_list func_args opt_with ProcedureStmt def_arg %type def_elem def_list definition def_name def_type DefineStmt %type opt_instead event event_object RuleActionList, %type RuleActionBlock RuleActionMulti join_list @@ -2208,11 +2208,12 @@ RecipeStmt: EXECUTE RECIPE recipe_name * [, iscachable]) * [arg is ( { , })] * as + * [, ] * *****************************************************************************/ ProcedureStmt: CREATE FUNCTION func_name func_args - RETURNS func_return opt_with AS Sconst LANGUAGE Sconst + RETURNS func_return opt_with AS func_as LANGUAGE Sconst { $$ = cat2_str(cat5_str(cat5_str(make1_str("create function"), $3, $4, make1_str("returns"), $6), $7, make1_str("as"), $9, make1_str("language")), $11); } @@ -2230,6 +2231,12 @@ func_args_list: TypeId { $$ = $1; } { $$ = cat3_str($1, make1_str(","), $3); } ; +func_as: Sconst + { $$ = $1; } + | Sconst ',' Sconst + { $$ = cat3_str($1, make1_str(","), $3); } + ; + func_return: set_opt TypeId { $$ = cat2_str($1, $2); diff --git a/src/tools/backend/index.html b/src/tools/backend/index.html index e21efb71c19..499698412c8 100644 --- a/src/tools/backend/index.html +++ b/src/tools/backend/index.html @@ -11,28 +11,26 @@ by Bruce Momjian

-
-
flowchart
- - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + +
Click on an item to see more detail or look at the full