From cb8b40e6d5dbaa6a8ada4a6b1db2686a0f1e1f68 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 19 May 2001 09:01:10 +0000 Subject: [PATCH] Allow special '$libdir' macro to show up in object file path in CREATE FUNCTION command. Guard against trying to load a directory. Update documentation some. --- doc/src/sgml/dfunc.sgml | 21 +- doc/src/sgml/ref/create_function.sgml | 445 +++++++++++++++------------------- doc/src/sgml/ref/drop_function.sgml | 4 +- doc/src/sgml/ref/load.sgml | 183 +++----------- doc/src/sgml/xfunc.sgml | 131 +++++++--- doc/src/sgml/xplang.sgml | 6 +- src/backend/utils/fmgr/dfmgr.c | 119 ++++----- 7 files changed, 387 insertions(+), 522 deletions(-) diff --git a/doc/src/sgml/dfunc.sgml b/doc/src/sgml/dfunc.sgml index f9e37e1f28..2509ff8ea1 100644 --- a/doc/src/sgml/dfunc.sgml +++ b/doc/src/sgml/dfunc.sgml @@ -1,5 +1,5 @@ @@ -264,7 +264,7 @@ gcc -shared -o foo.so foo.o Postgres. When specifying the file name to the CREATE FUNCTION command, one must give it the name of the shared library file (ending in - .so) rather than the simple object file. + .so) rather than the intermediate object file. @@ -273,21 +273,8 @@ gcc -shared -o foo.so foo.o - Paths given to the CREATE FUNCTION command must - be absolute paths (i.e., start with /) that refer - to directories visible on the machine on which the - Postgres server is running. Relative - paths do in fact work, but are relative to the directory where the - database resides (which is generally invisible to the frontend - application). Obviously, it makes no sense to make the path - relative to the directory in which the user started the frontend - application, since the server could be running on a completely - different machine! The user id the - Postgres server runs as must be able to - traverse the path given to the CREATE FUNCTION - command and be able to read the shared library file. (Making the - file or a higher-level directory not readable and/or not executable - by the postgres user is a common mistake.) + Refer back to about where the + server expects to find the shared library files. - - CREATE FUNCTION - + CREATE FUNCTION SQL - Language Statements + - - CREATE FUNCTION - - - Defines a new function - + CREATE FUNCTION + Defines a new function + - - 2000-03-25 - - -CREATE FUNCTION name ( [ ftype [, ...] ] ) - RETURNS rtype - AS definition + +CREATE FUNCTION name ( [ argtype [, ...] ] ) + RETURNS rettype + AS 'definition' LANGUAGE 'langname' [ WITH ( attribute [, ...] ) ] -CREATE FUNCTION name ( [ ftype [, ...] ] ) - RETURNS rtype - AS obj_file , link_symbol - LANGUAGE 'langname' +CREATE FUNCTION name ( [ argtype [, ...] ] ) + RETURNS rettype + AS 'obj_file', 'link_symbol' + LANGUAGE 'langname' [ WITH ( attribute [, ...] ) ] - + + - - - 2000-03-25 - - - Inputs - - + + Description - - - name - - - The name of a function to create. - - - - - ftype - - - The data type(s) of the function's arguments, if any. - The input types may be base or complex types, or - opaque. - Opaque indicates that the function - accepts arguments of a non-SQL type such as char *. - - - - - rtype - - - The return data type. - The output type may be specified as a base type, complex type, - , - or . - The - modifier indicates that the function will return a set of items, - rather than a single item. - - - - - attribute - - - An optional piece of information about the function, used for - optimization. See below for details. - - - - - definition - - - A string defining the function; the meaning depends on the language. - It may be an internal function name, the path to an object file, - an SQL query, or text in a procedural language. - - - - - 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, that is the name of the function in the C - language source code. - - - - - langname - - - May be 'sql', - 'C', 'internal', - or 'plname', - where 'plname' - is the name of a created procedural language. See - - for details. - - - - - - - - - - 2000-03-25 - - - Outputs - - + + CREATE FUNCTION defines a new function. - - - -CREATE - - - - This is returned if the command completes successfully. - - - - - - - + + Parameters - - - 2000-03-25 - - - Description - - - CREATE FUNCTION allows a - Postgres user - to register a function - with the database. Subsequently, this user is considered the - owner of the function. + + name + + + + The name of a function to create. The name need not be unique, + because functions may be overloaded, but functions with the + same name must have different argument types. + + + + + + argtype + + + + The data type(s) of the function's arguments, if any. The + input types may be base or complex types, or + opaque. Opaque indicates + that the function accepts arguments of a non-SQL type such as + char *. + + + + + + rettype + + + + The return data type. The output type may be specified as a + base type, complex type, setof type, or + opaque. The setof + modifier indicates that the function will return a set of + items, rather than a single item. Functions with a declared + return type of opaque do not return a value. + These cannot be called directly; trigger functions make use of + this feature. + + + + + + definition + + + + A string defining the function; the meaning depends on the + language. It may be an internal function name, the path to an + object file, an SQL query, or text in a procedural language. + + + + + + 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, that is, the name of the function in the C + language source code. + + + + + + langname + + + + May be 'sql', 'C', + 'internal', or 'plname', where 'plname' is the name of a + created procedural language. See + + for details. + + + + + + attribute + + + + An optional piece of information about the function, used for + optimization. See below for details. + + + + + - - - 2000-08-24 - - - Function Attributes - + + The user that creates the function becomes the owner of the function. + - - The following items may appear in the WITH clause: + + The following attributes may appear in the WITH clause: @@ -214,17 +178,12 @@ CREATE - + - + - - - 2000-03-25 - - - Notes - + + Notes Refer to the chapter in the @@ -240,7 +199,7 @@ CREATE - The full SQL92 type syntax is allowed for + The full SQL type syntax is allowed for input arguments and return value. However, some details of the type specification (e.g., the precision field for numeric types) are the responsibility of the @@ -250,7 +209,7 @@ CREATE - Postgres allows function "overloading"; + 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. @@ -275,38 +234,45 @@ CREATE C-language implementation of each overloaded SQL function. - + + When repeated CREATE FUNCTION calls refer to + the same object file, the file is only loaded once. To unload and + reload the file (perhaps during development), use the command. + + + - - - Usage - + + Examples + To create a simple SQL function: - -CREATE FUNCTION one() RETURNS int4 - AS 'SELECT 1 AS RESULT' + +CREATE FUNCTION one() RETURNS integer + AS 'SELECT 1 AS RESULT;' LANGUAGE 'sql'; -SELECT one() AS answer; - +SELECT one() AS answer; + answer -------- 1 - - + + - This example creates a C function by calling a routine from a user-created - shared library. This particular routine calculates a check - digit and returns TRUE if the check digit in the function parameters - is correct. It is intended for use in a CHECK contraint. - - -CREATE FUNCTION ean_checkdigit(bpchar, bpchar) RETURNS boolean + The next example creates a C function by calling a routine from a + user-created shared library. This particular routine calculates a + check digit and returns TRUE if the check digit in the function + parameters is correct. It is intended for use in a CHECK + constraint. + + +CREATE FUNCTION ean_checkdigit(char, char) RETURNS boolean AS '/usr1/proj/bray/sql/funcs.so' LANGUAGE 'c'; CREATE TABLE product ( @@ -316,28 +282,28 @@ 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 + compiled from C source. For PostgreSQL to + find a type conversion function automatically, the SQL function has to have the same name as the return type, and so 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 declaration of the function is: - - + + + The C declaration of the function could be: + + Point * complex_to_point (Complex *z) { Point *p; @@ -348,58 +314,33 @@ Point * complex_to_point (Complex *z) return p; } - - - + + + - - - Compatibility - - - - - 2000-03-25 - - - SQL92 - + + Compatibility - - CREATE FUNCTION is - a Postgres language extension. - - - - - - 2000-03-25 - - - SQL/PSM - - + + A CREATE FUNCTION command is defined in SQL99. + The PostgreSQL version is similar but + not compatible. The attributes are not portable, neither are the + different available languages. + + - - - PSM stands for Persistent Stored Modules. It is a procedural - language. SQL/PSM is a standard to enable function extensibility. - - - - SQL/PSM CREATE FUNCTION has the following syntax: - -CREATE FUNCTION name - ( [ [ IN | OUT | INOUT ] type [, ...] ] ) - RETURNS rtype - LANGUAGE 'langname' - ESPECIFIC routine - SQL-statement - - - + + + See Also + + + , + , + PostgreSQL Programmer's Guide + + @@ -116,7 +116,7 @@ NOTICE RemoveFunction: Function "name Refer to - + for information on creating functions. diff --git a/doc/src/sgml/ref/load.sgml b/doc/src/sgml/ref/load.sgml index 8fb5fafdb8..13008586c3 100644 --- a/doc/src/sgml/ref/load.sgml +++ b/doc/src/sgml/ref/load.sgml @@ -1,184 +1,55 @@ - - LOAD - + LOAD SQL - Language Statements + - - LOAD - - - Dynamically loads an object file - + LOAD + Loads a shared object file + - - 1999-07-20 - - + LOAD 'filename' - - - - - 1998-09-01 - - - Inputs - - - - - filename - - - Object file for dynamic loading. - - - - - - - - - - 1998-09-24 - - - Outputs - - - - - - -LOAD - - - - Message returned on successful completion. - - - - - -ERROR: LOAD: could not open file 'filename' - - - - Message returned if the specified file is not found. The file must be visible - to the Postgres backend, - with the appropriate full path name specified, to avoid this message. - - - - - - + - - - 1998-09-24 - - - Description - + + Description - Loads an object (or ".o") file into the - Postgres backend address space. Once a - file is loaded, all functions in that file can be accessed. This - function is used in support of user-defined types and functions. + Loads a shared object file into the PostgreSQL backend's address + space. If the file had been loaded previously, it is first + unloaded. This command is primarily useful to unload and reload a + shared object file if it has been changed. To make use of the + shared object, a function needs to be declared using the command. + + + + Compatibility - If a file is not loaded using - LOAD, - the file will be loaded automatically the first time the - function is called by Postgres. - LOAD - can also be used to reload an object file if it has been edited and - recompiled. Only objects created from C language files are supported - at this time. + LOAD is a PostgreSQL + extension. + - - - 1998-09-24 - - - Notes - - - Functions in loaded object files should not call functions in other - object files loaded through the - LOAD - command. For example, all functions in file A should - call each other, functions in the standard or math libraries, or in - Postgres itself. They should not call functions defined in a different - loaded file B. - This is because if B is reloaded, the Postgres loader is - not able to relocate the calls from the functions in - A into - the new address space of B. - If B is not reloaded, however, there will - not be a problem. - - - Object files must be compiled to contain position independent code. - For example, - on DECstations you must use - /bin/cc - with the -G 0 option when compiling object files to be - loaded. - - - Note that if you are porting Postgres - to a new platform, LOAD - will have to work in order to support ADTs. - - - + + See Also - - - Usage - - Load the file /usr/postgres/demo/circle.o: - - -LOAD '/usr/postgres/demo/circle.o' - + , + PostgreSQL Programmer's Guide - - - - Compatibility - - - - - 1998-09-24 - - - SQL92 - - - There is no LOAD in SQL92. - - - @@ -29,14 +29,12 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.31 2001/02/15 19:03:35 tgl E procedural language - functions (functions written in, for example, PLTCL or PLSQL) + functions (functions written in, for example, PL/Tcl or PL/pgSQL) - programming - language functions (functions written in a compiled - programming language such as C) + C language functions @@ -371,16 +369,36 @@ SELECT clean_EMP(); - Compiled (C) Language Functions + C Language Functions - Functions written in C can be compiled into dynamically loadable - objects (also called shared libraries), and used to implement user-defined - SQL functions. The first time a user-defined function in a particular + User-defined functions can be written in C (or a language that can + be made compatible with C, such as C++). Such functions are + compiled into dynamically loadable objects (also called shared + libraries) and are loaded by the server on demand. This + distinguishes them from internal functions. + + + + Two different calling conventions are currently used for C functions. + The newer "version 1" calling convention is indicated by writing + a PG_FUNCTION_INFO_V1() macro call for the function, + as illustrated below. Lack of such a macro indicates an old-style + ("version 0") function. The language name specified in CREATE FUNCTION + is 'C' in either case. Old-style functions are now deprecated + because of portability problems and lack of functionality, but they + are still supported for compatibility reasons. + + + + Dynamic Loading + + + The first time a user-defined function in a particular loadable object file is called in a backend session, the dynamic loader loads that object file into memory so that the function can be called. The CREATE FUNCTION - for a user-defined function must therefore specify two pieces of + for a user-defined C function must therefore specify two pieces of information for the function: the name of the loadable object file, and the C name (link symbol) of the specific function to call within that object file. If the C name is not explicitly specified then @@ -397,35 +415,82 @@ SELECT clean_EMP(); - The string that specifies the object file (the first string in the AS - clause) should be the full path of the object - code file for the function, bracketed by single quote marks. If a - link symbol is given in the AS clause, the link symbol should also be - bracketed by single quote marks, and should be exactly the - same as the name of the function in the C source code. On Unix systems - the command nm will print all of the link - symbols in a dynamically loadable object. + The following algorithm is used to locate the shared object file + based on the name given in the CREATE FUNCTION + command: + + + + + If the name is an absolute file name, the given file is loaded. + + + + + + If the name starts with the string $libdir, + that part is replaced by the PostgreSQL library directory, + which is determined at build time. + + + + + + If the name does not contain a directory part, the file is + searched the path specified by the configuration variable + dynamic_library_path. + + + + + + Otherwise (the file was not found in the path, or it contains a + non-absolute directory part), the dynamic loader will try to + take the name as given, which will most likely fail. (It is + unreliable to depend on the current working directory.) + + + + + If this sequence does not work, the platform-specific shared + library file name extension (often .so) is + appended to the given name and this sequence is tried again. If + that fails as well, the load will fail. + - - - 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 user id the PostgreSQL server runs + as must be able to traverse the path to the file you intend to + load. Making the file or a higher-level directory not readable + and/or not executable by the postgres user is a + common mistake. + + + + + In any case, the file name that is specified in the + CREATE FUNCTION command is recorded literally + in the system catalogs, so if the file needs to be loaded again + the same procedure is applied. - Two different calling conventions are currently used for C functions. - The newer "version 1" calling convention is indicated by writing - a PG_FUNCTION_INFO_V1() macro call for the function, - as illustrated below. Lack of such a macro indicates an old-style - ("version 0") function. The language name specified in CREATE FUNCTION - is 'C' in either case. Old-style functions are now deprecated - because of portability problems and lack of functionality, but they - are still supported for compatibility reasons. + It is recommended to locate shared libraries either relative to + $libdir or through the dynamic library path. + This simplifies version upgrades if the new installation is at a + different location. + + + PostgreSQL will not compile a function + automatically; it must be compiled before it is used in a CREATE + FUNCTION command. See for additional information. + + + + Base Types in C-Language Functions diff --git a/doc/src/sgml/xplang.sgml b/doc/src/sgml/xplang.sgml index 8e72b93189..46a59c6172 100644 --- a/doc/src/sgml/xplang.sgml +++ b/doc/src/sgml/xplang.sgml @@ -1,5 +1,5 @@ @@ -130,13 +130,13 @@ CREATE TRUSTED PROCEDURAL LANGUAGE ' CREATE FUNCTION plpgsql_call_handler () RETURNS OPAQUE AS - '/usr/local/pgsql/lib/plpgsql.so' LANGUAGE 'C'; + '$libdir/plpgsql' LANGUAGE 'C'; - + The command CREATE TRUSTED PROCEDURAL LANGUAGE 'plpgsql' diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index 695fb1ed76..0448632aad 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.49 2001/05/17 17:44:18 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.50 2001/05/19 09:01:10 petere Exp $ * *------------------------------------------------------------------------- */ @@ -51,7 +51,7 @@ char * Dynamic_library_path; static bool file_exists(const char *name); static char * find_in_dynamic_libpath(const char * basename); static char * expand_dynamic_library_name(const char *name); - +static char * substitute_libpath_macro(const char * name); /* * Load the specified dynamic-link library file, and look for a function @@ -210,7 +210,7 @@ file_exists(const char *name) AssertArg(name != NULL); if (stat(name, &st) == 0) - return true; + return S_ISDIR(st.st_mode) ? false : true; else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES)) elog(ERROR, "stat failed on %s: %s", name, strerror(errno)); @@ -234,15 +234,14 @@ file_exists(const char *name) * the name. Else (no slash) try to expand using search path (see * find_in_dynamic_libpath below); if that works, return the fully * expanded file name. If the previous failed, append DLSUFFIX and - * try again. If all fails, return NULL. The return value is - * palloc'ed. + * try again. If all fails, return NULL. */ static char * expand_dynamic_library_name(const char *name) { bool have_slash; char * new; - size_t len; + char * full; AssertArg(name); @@ -250,28 +249,23 @@ expand_dynamic_library_name(const char *name) if (!have_slash) { - char * full; - full = find_in_dynamic_libpath(name); if (full) return full; } else { - if (file_exists(name)) - return pstrdup(name); + full = substitute_libpath_macro(name); + if (file_exists(full)) + return full; } - len = strlen(name); - - new = palloc(len + strlen(DLSUFFIX) + 1); + new = palloc(strlen(name)+ strlen(DLSUFFIX) + 1); strcpy(new, name); - strcpy(new + len, DLSUFFIX); + strcat(new, DLSUFFIX); if (!have_slash) { - char * full; - full = find_in_dynamic_libpath(new); pfree(new); if (full) @@ -279,8 +273,9 @@ expand_dynamic_library_name(const char *name) } else { - if (file_exists(new)) - return new; + full = substitute_libpath_macro(new); + if (file_exists(full)) + return full; } return NULL; @@ -288,6 +283,40 @@ expand_dynamic_library_name(const char *name) +static char * +substitute_libpath_macro(const char * name) +{ + size_t macroname_len; + char * replacement = NULL; + + AssertArg(name != NULL); + + if (strlen(name) == 0 || name[0] != '$') + return pstrdup(name); + + macroname_len = strcspn(name + 1, "/") + 1; + + if (strncmp(name, "$libdir", macroname_len)==0) + replacement = LIBDIR; + else + elog(ERROR, "invalid macro name in dynamic library path"); + + if (name[macroname_len] == '\0') + return replacement; + else + { + char * new; + + new = palloc(strlen(replacement) + (strlen(name) - macroname_len) + 1); + + strcpy(new, replacement); + strcat(new, name + macroname_len); + + return new; + } +} + + /* * Search for a file called 'basename' in the colon-separated search * path 'path'. If the file is found, the full file name is returned @@ -312,55 +341,26 @@ find_in_dynamic_libpath(const char * basename) baselen = strlen(basename); do { + char * piece; + const char * mangled; + len = strcspn(p, ":"); if (len == 0) elog(ERROR, "zero length dynamic_library_path component"); - /* substitute special value */ - if (p[0] == '$') - { - size_t varname_len = strcspn(p + 1, "/") + 1; - const char * replacement = NULL; - size_t repl_len; + piece = palloc(len + 1); + strncpy(piece, p, len); + piece[len] = '\0'; - if (strncmp(p, "$libdir", varname_len)==0) - replacement = LIBDIR; - else - elog(ERROR, "invalid dynamic_library_path specification"); + mangled = substitute_libpath_macro(piece); - repl_len = strlen(replacement); + /* only absolute paths */ + if (mangled[0] != '/') + elog(ERROR, "dynamic_library_path component is not absolute"); - if (p[varname_len] == '\0') - { - full = palloc(repl_len + 1 + baselen + 1); - snprintf(full, repl_len + 1 + baselen + 1, - "%s/%s", replacement, basename); - } - else - { - full = palloc(repl_len + (len - varname_len) + 1 + baselen + 1); - - strcpy(full, replacement); - strncat(full, p + varname_len, len - varname_len); - full[repl_len + (len - varname_len)] = '\0'; - strcat(full, "/"); - strcat(full, basename); - } - } - - /* regular case */ - else - { - /* only absolute paths */ - if (p[0] != '/') - elog(ERROR, "dynamic_library_path component is not absolute"); - - full = palloc(len + 1 + baselen + 1); - strncpy(full, p, len); - full[len] = '/'; - strcpy(full + len + 1, basename); - } + full = palloc(strlen(mangled) + 1 + baselen + 1); + sprintf(full, "%s/%s", mangled, basename); if (DebugLvl > 1) elog(DEBUG, "find_in_dynamic_libpath: trying %s", full); @@ -368,6 +368,7 @@ find_in_dynamic_libpath(const char * basename) if (file_exists(full)) return full; + pfree(piece); pfree(full); if (p[len] == '\0') break; -- 2.11.0