mirror of https://github.com/postgres/postgres
there's no shared libpython. Test suite works as well. Also, add some documentation.REL7_2_STABLE
parent
02549a2d2c
commit
bbc3920fe9
@ -1,50 +1,88 @@ |
||||
# |
||||
# Autoconf macros for configuring the build of Python extension modules |
||||
# |
||||
# $Header: /cvsroot/pgsql/config/python.m4,v 1.1 2000/06/10 18:01:35 petere Exp $ |
||||
# $Header: /cvsroot/pgsql/config/python.m4,v 1.2 2001/05/12 17:49:32 petere Exp $ |
||||
# |
||||
|
||||
# PGAC_PROG_PYTHON |
||||
# PGAC_PATH_PYTHON |
||||
# ---------------- |
||||
# Look for Python and set the output variable `PYTHON' |
||||
# to `python' if found, empty otherwise. |
||||
AC_DEFUN([PGAC_PROG_PYTHON], |
||||
[AC_CHECK_PROG(PYTHON, python, python)]) |
||||
AC_DEFUN([PGAC_PATH_PYTHON], |
||||
[AC_PATH_PROG(PYTHON, python) |
||||
if test x"$PYTHON" = x""; then |
||||
AC_MSG_ERROR([Python not found]) |
||||
fi |
||||
]) |
||||
|
||||
|
||||
# _PGAC_CHECK_PYTHON_DIRS |
||||
# ----------------------- |
||||
# Determine the name of various directory of a given Python installation. |
||||
AC_DEFUN([_PGAC_CHECK_PYTHON_DIRS], |
||||
[AC_REQUIRE([PGAC_PATH_PYTHON]) |
||||
python_version=`${PYTHON} -c "import sys; print sys.version[[:3]]"` |
||||
python_prefix=`${PYTHON} -c "import sys; print sys.prefix"` |
||||
python_execprefix=`${PYTHON} -c "import sys; print sys.exec_prefix"` |
||||
python_configdir="${python_execprefix}/lib/python${python_version}/config" |
||||
python_moduledir="${python_prefix}/lib/python${python_version}" |
||||
python_includedir="${python_prefix}/include/python${python_version}" |
||||
python_dynlibdir="${python_execprefix}/lib/python${python_version}/lib-dynload" |
||||
|
||||
AC_SUBST(python_version)[]dnl |
||||
AC_SUBST(python_prefix)[]dnl |
||||
AC_SUBST(python_execprefix)[]dnl |
||||
AC_SUBST(python_configdir)[]dnl |
||||
AC_SUBST(python_moduledir)[]dnl |
||||
AC_SUBST(python_includedir)[]dnl |
||||
AC_SUBST(python_dynlibdir)[]dnl |
||||
])# _PGAC_CHECK_PYTHON_DIRS |
||||
|
||||
|
||||
# PGAC_PATH_PYTHONDIR |
||||
# ------------------- |
||||
# Finds the names of various install dirs and helper files |
||||
# necessary to build a Python extension module. |
||||
# PGAC_CHECK_PYTHON_MODULE_SETUP |
||||
# ------------------------------ |
||||
# Finds things required to build a Python extension module, in |
||||
# particular the makefile. |
||||
# |
||||
# It would be nice if we could check whether the current setup allows |
||||
# the build of the shared module. Future project. |
||||
AC_DEFUN([PGAC_PATH_PYTHONDIR], |
||||
[AC_REQUIRE([PGAC_PROG_PYTHON]) |
||||
[if test "${PYTHON+set}" = set ; then |
||||
python_version=`${PYTHON} -c "import sys; print sys.version[:3]"` |
||||
python_prefix=`${PYTHON} -c "import sys; print sys.prefix"` |
||||
python_execprefix=`${PYTHON} -c "import sys; print sys.exec_prefix"` |
||||
python_configdir="${python_execprefix}/lib/python${python_version}/config" |
||||
python_moduledir="${python_prefix}/lib/python${python_version}" |
||||
python_extmakefile="${python_configdir}/Makefile.pre.in"] |
||||
|
||||
AC_MSG_CHECKING(for Python extension makefile) |
||||
if test -f "${python_extmakefile}" ; then |
||||
AC_MSG_RESULT(found) |
||||
else |
||||
AC_MSG_RESULT(no) |
||||
AC_MSG_ERROR( |
||||
[The Python extension makefile was expected at \`${python_extmakefile}\' |
||||
but does not exist. This means the Python module cannot be built automatically.]) |
||||
fi |
||||
|
||||
AC_SUBST(python_version) |
||||
AC_SUBST(python_prefix) |
||||
AC_SUBST(python_execprefix) |
||||
AC_SUBST(python_configdir) |
||||
AC_SUBST(python_moduledir) |
||||
AC_SUBST(python_extmakefile) |
||||
AC_DEFUN([PGAC_CHECK_PYTHON_MODULE_SETUP], |
||||
[AC_REQUIRE([_PGAC_CHECK_PYTHON_DIRS]) |
||||
AC_MSG_CHECKING([for makefile to build Python module]) |
||||
python_makefile_pre_in="${python_configdir}/Makefile.pre.in" |
||||
|
||||
if test -f "${python_makefile_pre_in}" ; then |
||||
AC_MSG_RESULT([${python_makefile_pre_in}]) |
||||
else |
||||
AC_MSG_ERROR([Python not found]) |
||||
fi])# PGAC_PATH_PYTHONDIR |
||||
AC_MSG_RESULT(no) |
||||
AC_MSG_ERROR( |
||||
[The file |
||||
${python_makefile_pre_in} |
||||
required to build Python modules does not exist. Make sure that you have |
||||
a full Python installation and that this is the right location.]) |
||||
fi |
||||
|
||||
AC_SUBST(python_makefile_pre_in)[]dnl |
||||
])# PGAC_CHECK_PYTHON_MODULE_SETUP |
||||
|
||||
|
||||
# PGAC_CHECK_PYTHON_EMBED_SETUP |
||||
# ----------------------------- |
||||
# Courtesy of the INN 2.3.1 package... |
||||
AC_DEFUN([PGAC_CHECK_PYTHON_EMBED_SETUP], |
||||
[AC_REQUIRE([_PGAC_CHECK_PYTHON_DIRS]) |
||||
AC_MSG_CHECKING([how to link an embedded Python application]) |
||||
|
||||
_python_libs=`grep '^LIBS=' $python_configdir/Makefile | sed 's/^.*=//'` |
||||
_python_libc=`grep '^LIBC=' $python_configdir/Makefile | sed 's/^.*=//'` |
||||
_python_libm=`grep '^LIBM=' $python_configdir/Makefile | sed 's/^.*=//'` |
||||
_python_liblocalmod=`grep '^LOCALMODLIBS=' $python_configdir/Makefile | sed 's/^.*=//'` |
||||
_python_libbasemod=`grep '^BASEMODLIBS=' $python_configdir/Makefile | sed 's/^.*=//'` |
||||
|
||||
pgac_tab=" " # tab character |
||||
python_libspec=`echo X"-L$python_configdir $_python_libs $_python_libc $_python_libm -lpython$python_version $_python_liblocalmod $_python_libbasemod" | sed -e 's/^X//' -e "s/[[ $pgac_tab]][[ $pgac_tab]]*/ /g"` |
||||
|
||||
AC_MSG_RESULT([${python_libspec}]) |
||||
|
||||
AC_SUBST(python_libspec)[]dnl |
||||
])# PGAC_CHECK_PYTHON_EMBED_SETUP |
||||
|
@ -0,0 +1,152 @@ |
||||
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/plpython.sgml,v 1.1 2001/05/12 17:49:32 petere Exp $ --> |
||||
|
||||
<chapter id="plpython"> |
||||
<title>PL/Python - Python Procedural Language</title> |
||||
|
||||
<note> |
||||
<para> |
||||
This chapter is not fully developed yet. |
||||
</para> |
||||
</note> |
||||
|
||||
<sect1 id="plpython-install"> |
||||
<title>Installation</title> |
||||
|
||||
<para> |
||||
... needs to be worked out. |
||||
</para> |
||||
</sect1> |
||||
|
||||
<sect1 id="plpython-using"> |
||||
<title>Using</title> |
||||
|
||||
<para> |
||||
There are sample functions in |
||||
<filename>plpython_function.sql</filename>. The Python code you |
||||
write gets transformed into a function. E.g., |
||||
<programlisting> |
||||
CREATE FUNCTION myfunc(text) RETURNS text AS |
||||
'return args[0]' |
||||
LANGUAGE 'plpython'; |
||||
</programlisting> |
||||
|
||||
gets transformed into |
||||
|
||||
<programlisting> |
||||
def __plpython_procedure_myfunc_23456(): |
||||
return args[0] |
||||
</programlisting> |
||||
|
||||
where 23456 is the Oid of the function. |
||||
</para> |
||||
|
||||
<para> |
||||
If you do not provide a return value, Python returns the default |
||||
<symbol>None</symbol> which may or may not be what you want. The |
||||
language module translates Python's None into SQL NULL. |
||||
</para> |
||||
|
||||
<para> |
||||
PostgreSQL function variables are available in the global |
||||
<varname>args</varname> list. In the <function>myfunc</function> |
||||
example, args[0] contains whatever was passed in as the text |
||||
argument. For <literal>myfunc2(text, int4)</literal>, args[0] |
||||
would contain the text variable and args[1] the int4 variable. |
||||
</para> |
||||
|
||||
<para> |
||||
The global dictionary SD is available to store data between |
||||
function calls. This variable is private static data. The global |
||||
dictionary GD is public data, available to all python functions |
||||
within a backend. Use with care. When the function is used in a |
||||
trigger, the triggers tuples are in TD["new"] and/or TD["old"] |
||||
depending on the trigger event. Return 'None' or "OK" from the |
||||
python function to indicate the tuple is unmodified, "SKIP" to |
||||
abort the event, or "MODIFIED" to indicate you've modified the |
||||
tuple. If the trigger was called with arguments they are available |
||||
in TD["args"][0] to TD["args"][(n -1)] |
||||
</para> |
||||
|
||||
<para> |
||||
Each function gets its own restricted execution object in the |
||||
Python interpreter, so that global data and function arguments from |
||||
<function>myfunc</function> are not available to |
||||
<function>myfunc2</function>. The exception is the data in the GD |
||||
dictionary, as mentioned above. |
||||
</para> |
||||
|
||||
<para> |
||||
The PL/Python language module automatically imports a Python module |
||||
called <literal>plpy</literal>. The functions and constants in |
||||
this module are available to you in the Python code as |
||||
<literal>plpy.<replaceable>foo</replaceable></literal>. At present |
||||
<literal>plpy</literal> implements the functions |
||||
<literal>plpy.error("msg")</literal>, |
||||
<literal>plpy.fatal("msg")</literal>, |
||||
<literal>plpy.debug("msg")</literal>, and |
||||
<literal>plpy.notice("msg")</literal>. They are mostly equivalent |
||||
to calling <literal>elog(<replaceable>LEVEL</>, "msg")</literal>, |
||||
where <replaceable>LEVEL</> is DEBUG, ERROR, FATAL or NOTICE. |
||||
<function>plpy.error</function> and <function>plpy.fatal</function> |
||||
actually raise a Python exception which, if uncaught, causes the |
||||
PL/Python module to call <literal>elog(ERROR, msg)</literal> when |
||||
the function handler returns from the Python interpreter. Long |
||||
jumping out of the Python interpreter is probably not good. |
||||
<literal>raise plpy.ERROR("msg")</literal> and <literal>raise |
||||
plpy.FATAL("msg")</literal> are equivalent to calling |
||||
<function>plpy.error</function> or <function>plpy.fatal</function>. |
||||
</para> |
||||
|
||||
<para> |
||||
Additionally, the plpy module provides two functions called |
||||
<function>execute</function> and <function>prepare</function>. |
||||
Calling <function>plpy.execute</function> with a query string, and |
||||
an optional limit argument, causes that query to be run, and the |
||||
result returned in a result object. The result object emulates a |
||||
list or dictionary object. The result object can be accessed by |
||||
row number, and field name. It has these additional methods: |
||||
<function>nrows()</function> which returns the number of rows |
||||
returned by the query, and <function>status</function> which is the |
||||
<function>SPI_exec</function> return variable. The result object |
||||
can be modified. |
||||
|
||||
<programlisting> |
||||
rv = plpy.execute("SELECT * FROM my_table", 5) |
||||
</programlisting> |
||||
returns up to 5 rows from my_table. Ff my_table has a column |
||||
my_field it would be accessed as |
||||
<programlisting> |
||||
foo = rv[i]["my_field"] |
||||
</programlisting> |
||||
The second function <function>plpy.prepare</function> is called |
||||
with a query string, and a list of argument types if you have bind |
||||
variables in the query. |
||||
<programlisting> |
||||
plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", [ "text" ]) |
||||
</programlisting> |
||||
text is the type of the variable you will be passing as $1. After |
||||
preparing you use the function <function>plpy.execute</function> to |
||||
run it. |
||||
<programlisting> |
||||
rv = plpy.execute(plan, [ "name" ], 5) |
||||
</programlisting> |
||||
The limit argument is optional in the call to |
||||
<function>plpy.execute</function>. |
||||
</para> |
||||
|
||||
<para> |
||||
When you prepare a plan using the PL/Python module it is |
||||
automatically saved. Read the SPI documentation (<xref |
||||
linkend="spi">) for a description of what this means. The take |
||||
home message is if you do |
||||
<programlisting> |
||||
plan = plpy.prepare("SOME QUERY") |
||||
plan = plpy.prepare("SOME OTHER QUERY") |
||||
</programlisting> |
||||
you are leaking memory, as I know of no way to free a saved plan. |
||||
The alternative of using unsaved plans it even more painful (for |
||||
me). |
||||
</para> |
||||
</sect1> |
||||
|
||||
</chapter> |
@ -1,9 +1,25 @@ |
||||
<html> |
||||
<head><title>TODO</title></head> |
||||
<body bgcolor="white"> |
||||
In no special order<br> |
||||
<li>allow arrays as function arguments and return values (almost done). |
||||
<li>more and better documentation. |
||||
<li>improve/automate configuration. |
||||
<li>??? |
||||
</body> |
||||
In no particular order... |
||||
|
||||
* Allow arrays as function arguments and return values. (almost done) |
||||
|
||||
* Create a new restricted execution class that will allow me to pass |
||||
function arguments in as locals. Passing them as globals means |
||||
functions cannot be called recursively. |
||||
|
||||
* Functions cache the input and output functions for their arguments, |
||||
so the following will make PostgreSQL unhappy: |
||||
|
||||
create table users (first_name text, last_name text); |
||||
create function user_name(user) returns text as 'mycode' language 'plpython'; |
||||
select user_name(user) from users; |
||||
alter table add column user_id integer; |
||||
select user_name(user) from users; |
||||
|
||||
You have to drop and create the function(s) each time its arguments |
||||
are modified (not nice), or don't cache the input and output functions |
||||
(slower?), or check if the structure of the argument has been |
||||
altered (is this possible, easy, quick?) and recreate cache. |
||||
|
||||
* Better documentation |
||||
|
||||
* Add a DB-API compliant interface on top of the SPI interface. |
||||
|
Loading…
Reference in new issue