diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml index 84f4f5c958fefbcc524f119aaf345a4da3534894..b22b9e4088f893a82870649cf044000f8b055187 100644 --- a/doc/src/sgml/ref/create_function.sgml +++ b/doc/src/sgml/ref/create_function.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.9 1999/07/22 15:09:07 thomas Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.10 1999/09/28 04:34:39 momjian Exp $ Postgres documentation --> @@ -25,8 +25,14 @@ Postgres documentation <synopsis> CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">ftype</replaceable> [, ...] ] ) RETURNS <replaceable class="parameter">rtype</replaceable> - AS <replaceable class="parameter">definition</replaceable> + AS <replaceable class="parameter">definition</replaceable> LANGUAGE '<replaceable class="parameter">langname</replaceable>' + + +CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">ftype</replaceable> [, ...] ] ) + RETURNS <replaceable class="parameter">rtype</replaceable> + AS <replaceable class="parameter">obj_file</replaceable> , <replaceable class="parameter">link_symbol</replaceable> + LANGUAGE 'c' </synopsis> <refsect2 id="R2-SQL-CREATEFUNCTION-1"> @@ -83,6 +89,22 @@ CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceab </para> </listitem> </varlistentry> + <varlistentry> + <term><replaceable class="parameter">obj_file</replaceable> , <replaceable class="parameter">link_symbol</replaceable></term> + <listitem> + <para> + This form of the <command>AS</command> 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 <replaceable + class="parameter">obj_file</replaceable> is the name of the file + containing the dynamically loadable object, and <replaceable + class="parameter">link_symbol</replaceable>, is the object's link + symbol which is the same as the name of the function in the C + language source code. + </para> + </listitem> + </varlistentry> <varlistentry> <term><replaceable class="parameter">langname</replaceable></term> <listitem> @@ -165,10 +187,10 @@ CREATE <para> <productname>Postgres</productname> 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 <literal>internal</literal> - and C-language functions, however. - </para> + so long as they have distinct argument types. This facility must + be used with caution for <literal>internal</literal> and + C-language functions, however. + </para> <para> Two <literal>internal</literal> @@ -181,18 +203,15 @@ CREATE </para> <para> - 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 <command>AS</command> clause in the + <command>CREATE FUNCTION</command> syntax to ensure that + overloaded SQL functions names are resolved to the correct + dynamically linked objects. </para> + <para> A C function cannot return a set of values. </para> @@ -227,7 +246,6 @@ SELECT one() AS answer; is correct. It is intended for use in a CHECK contraint. </para> <programlisting> - <userinput> 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)) ); - </userinput> </programlisting> + + + <para> + 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 <productname>Postgres</productname> 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 <command>AS</command> clause in the SQL definition + </para> + <programlisting> +CREATE FUNCTION point(complex) RETURNS point + AS '/home/bernie/pgsql/lib/complex.so', 'complex_to_point' + LANGUAGE 'c'; + </programlisting> + <para> + The C decalaration of the function is: + </para> + <programlisting> +Point * complex_to_point (Complex *z) +{ + Point *p; + + p = (Point *) palloc(sizeof(Point)); + p->x = z->x; + p->y = z->y; + + return p; +} + </programlisting> + + </refsect1> <refsect1 id="R1-SQL-CREATEFUNCTION-4"> @@ -283,8 +334,7 @@ CREATE TABLE product ( SQL/PSM <command>CREATE FUNCTION</command> has the following syntax: <synopsis> CREATE FUNCTION <replaceable class="parameter">name</replaceable> - ( [ [ IN | OUT | INOUT ] <replaceable class="parameter">eter</replaceable>eable>eable> <replaceable - class="parameter">type</replaceable> [, ...] ] ) + ( [ [ IN | OUT | INOUT ] <replaceable class="parameter">type</replaceable> [, ...] ] ) RETURNS <replaceable class="parameter">rtype</replaceable> LANGUAGE '<replaceable class="parameter">langname</replaceable>' ESPECIFIC <replaceable class="parameter">routine</replaceable> diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index 036d029d818f70a8ba4584874cf83463e0e603c2..879f6f6667245977dcb027163e50dde4ece8edfb 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.*) <title>Compiled (C) Language Functions</title> <para> - 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 + <productname>Postgres</productname> executable. The SQL syntax + for the <xref linkend="sql-createfunction-title" + endterm="sql-createfunction-title"> 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. </para> <para> - The string which specifies the object file (the string in the AS clause) - should be the <emphasis>full path</emphasis> - of the object code file for the function, bracketed by quotation - marks. (<productname>Postgres</productname> 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 <emphasis>full path</emphasis> 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 <command>nm</command> will print all of the link + symbols in a dynamically loadable object. + (<productname>Postgres</productname> will not compile a function + automatically; it must be compiled before it is used in a CREATE + FUNCTION command. See below for additional information.) </para> <sect2> @@ -960,10 +978,13 @@ memmove(destination->data, buffer, 40); <title>Name Space Conflicts</title> <para> - As of <productname>Postgres</productname> v6.5, - <command>CREATE FUNCTION</command> 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 <productname>Postgres</productname> v6.6, the alternative + form of the AS clause for the SQL <command>CREATE + FUNCTION</command> command described in <xref + linkend="sql-createfunction-title" endterm="sql-createfunction-title"> + decouples the SQL function name from the function name in the C + source code. This is now the preferred technique to accomplish + function overloading. </para> <sect3> diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index c7dc7d3ad1c54499e93cfc3ea69f0796329b7c95..509d5026d301a55e73b1872074f95ae779b243f4 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 <object file name> [, <link symbol name> ] + * + * In all other cases + * + * AS <object reference, or sql code> + * + */ 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 32c46e05d1c06ce161c0be4d99f86438dbe174db..67d7ac00cd1f1cee4c55ef678a665851517621dc 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 <list> 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 dcf2814171b583600a8b974c9b43dfb63eeb1ab6..171f269127d11f79a8136a977b11e4424933d634 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 020d8e450e111f93c404450ac17af06e8f603d6a..63268c2cbd9ee7ffaa02f927175c80df2e2fc4cf 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 66c5a9132aab45f21a3c399adfc1fb8e0527fec2..4bf879137ac26436a34cf149531eda6dbf0a1433 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 6151a6328d848eb70532a786800ad7051841df70..9ba3daacb6403c5078e56b21d597e35349bb51a9 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 <str> opt_analyze opt_va_list va_list ExplainStmt index_params %type <str> index_list func_index index_elem opt_type opt_class access_method_clause %type <str> index_opt_unique IndexStmt set_opt func_return def_rest -%type <str> func_args_list func_args opt_with ProcedureStmt def_arg +%type <str> func_as func_args_list func_args opt_with ProcedureStmt def_arg %type <str> def_elem def_list definition def_name def_type DefineStmt %type <str> opt_instead event event_object RuleActionList, %type <str> RuleActionBlock RuleActionMulti join_list @@ -2208,11 +2208,12 @@ RecipeStmt: EXECUTE RECIPE recipe_name * [, iscachable]) * [arg is (<type-1> { , <type-n>})] * as <filename or code in language as appropriate> + * [, <link name for dynamic loader>] * *****************************************************************************/ 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 e21efb71c1930488566aa89407a67e364d48dfab..499698412c8dd8e33d26ce589ce189663901ca27 100644 --- a/src/tools/backend/index.html +++ b/src/tools/backend/index.html @@ -11,28 +11,26 @@ by Bruce Momjian </H2> <P> <CENTER> -<BR> -<BR> <IMG src="flow.gif" usemap="#flowmap" alt="flowchart" border=0> </CENTER> <MAP name="flowmap"> -<AREA COORDS="70,0,230,40" HREF="backend_dirs.html#main"> -<AREA COORDS="70,80,230,120" HREF="backend_dirs.html#postmaster"> -<AREA COORDS="330,40,490,80" HREF="backend_dirs.html#libpq"> -<AREA COORDS="70,160,230,200" HREF="backend_dirs.html#tcop"> -<AREA COORDS="330,160,490,200" HREF="backend_dirs.html#tcop"> -<AREA COORDS="70,260,230,300" HREF="backend_dirs.html#parser"> -<AREA COORDS="70,340,230,380" HREF="backend_dirs.html#tcop"> -<AREA COORDS="70,420,230,460" HREF="backend_dirs.html#optimizer"> -<AREA COORDS="70,400,230,540" HREF="backend_dirs.html#optimizer/plan"> -<AREA COORDS="70,580,230,620" HREF="backend_dirs.html#executor"> -<AREA COORDS="330,340,490,380" HREF="backend_dirs.html#commands"> -<AREA COORDS="0,690,160,740" HREF="backend_dirs.html#utils"> -<AREA COORDS="210,690,370,730" HREF="backend_dirs.html#catalog"> -<AREA COORDS="420,690,590,740" HREF="backend_dirs.html#storage"> -<AREA COORDS="100,770,270,820" HREF="backend_dirs.html#access"> -<AREA COORDS="330,770,490,820" HREF="backend_dirs.html#nodes"> -<AREA COORDS="10,860,170,900" HREF="backend_dirs.html#bootstrap"> +<AREA COORDS="125,35,245,65" HREF="backend_dirs.html#main"> +<AREA COORDS="125,100,245,125" HREF="backend_dirs.html#postmaster"> +<AREA COORDS="325,65,450,95" HREF="backend_dirs.html#libpq"> +<AREA COORDS="125,160,245,190" HREF="backend_dirs.html#tcop"> +<AREA COORDS="325,160,450,190" HREF="backend_dirs.html#tcop"> +<AREA COORDS="125,240,245,265" HREF="backend_dirs.html#parser"> +<AREA COORDS="125,300,250,330" HREF="backend_dirs.html#tcop"> +<AREA COORDS="125,360,250,390" HREF="backend_dirs.html#optimizer"> +<AREA COORDS="125,425,245,455" HREF="backend_dirs.html#optimizer/plan"> +<AREA COORDS="125,490,245,515" HREF="backend_dirs.html#executor"> +<AREA COORDS="325,300,450,330" HREF="backend_dirs.html#commands"> +<AREA COORDS="75,575,195,605" HREF="backend_dirs.html#utils"> +<AREA COORDS="235,575,360,605" HREF="backend_dirs.html#catalog"> +<AREA COORDS="405,575,525,605" HREF="backend_dirs.html#storage"> +<AREA COORDS="155,635,275,665" HREF="backend_dirs.html#access"> +<AREA COORDS="325,635,450,665" HREF="backend_dirs.html#nodes"> +<AREA COORDS="75,705,200,730" HREF="backend_dirs.html#bootstrap"> </MAP> <CENTER><EM> Click on an item to see more detail or look at the full