|
| 1 | +PL/Python - Python Procedural Language for PostgreSQL |
| 2 | +----------------------------------------------------- |
| 3 | +$Id: README,v 1.2 2001/05/14 22:06:50 petere Exp $ |
1 | 4 |
|
2 | | -*** INSTALLING *** |
| 5 | +Installation: |
3 | 6 |
|
4 | | - 0) Build, install or borrow postgresql 7.1, not 7.0. I've got |
5 | | -a language module for 7.0, but it has no SPI interface. Build is best |
6 | | -because it will allow you to do |
| 7 | +configure --with-python |
| 8 | +cd src/pl/plpython |
| 9 | +gmake |
| 10 | +gmake install |
7 | 11 |
|
8 | | - "cd postgres/src/" |
9 | | - "patch -p2 < dynloader.diff" |
| 12 | +Test: |
10 | 13 |
|
11 | | -or if that fails open linux.h in src/backend/ports/dynloader and |
12 | | -change the pg_dlopen define from |
| 14 | +# have postmaster running... |
| 15 | +gmake installcheck |
13 | 16 |
|
14 | | -#define pg_dlopen(f) dlopen(f, 2) |
| 17 | +Enable language: |
15 | 18 |
|
16 | | -to |
| 19 | +createlang plpython dbname |
17 | 20 |
|
18 | | -#define pg_dlopen(f) dlopen(f, (RTLD_NOW|RTLD_GLOBAL)) |
19 | 21 |
|
20 | | -adding the RTLD_GLOBAL flag to the dlopen call allows libpython to |
21 | | -properly resolve symbols when it loads dynamic module. If you can't |
22 | | -patch and rebuild postgres read about DLHACK in the next section. |
| 22 | +Note that PL/Python is currently not built automatically because the |
| 23 | +code is new and there are some portability issues. |
23 | 24 |
|
24 | | - 1) Edit the Makefile. Basically select python 2.0 or 1.5, and set |
25 | | -the include file locations for postgresql and python. If you can't |
26 | | -patch linux.h (or whatever file is appropriate for your architecture) |
27 | | -to add RTLD_GLOBAL to the pg_dlopen/dlopen function and rebuild |
28 | | -postgres. You must uncomment the DLHACK and DLDIR variables. You may |
29 | | -need to alter the DLDIR and add shared modules to DLHACK. This |
30 | | -explicitly links the shared modules to the plpython.so file, and |
31 | | -allows libpython find required symbols. However you will NOT be able |
32 | | -to import any C modules that are not explicitly linked to |
33 | | -plpython.so. Module dependencies get ugly, and all in all it's a |
34 | | -crude hack. |
| 25 | +A default Python installation does not provide a shared libpython |
| 26 | +library. This is not a problem on many platforms (although it makes |
| 27 | +things less efficient), but on some platforms (especially HP-UX) the |
| 28 | +link will fail outright. |
35 | 29 |
|
36 | | - 2) Run make. |
| 30 | +To create a shared libpython, see this web page for hints: |
37 | 31 |
|
38 | | - 3) Copy 'plpython.so' to '/usr/local/lib/postgresql/lang/'. |
39 | | -The scripts 'update.sh' and 'plpython_create.sql' are hard coded to |
40 | | -look for it there, if you want to install the module elsewhere edit |
41 | | -them. |
| 32 | +http://www.python.org/cgi-bin/faqw.py?req=show&file=faq03.030.htp |
42 | 33 |
|
43 | | - 4) Optionally type 'test.sh', this will create a new database |
44 | | -'pltest' and run some checks. (more checks needed) |
| 34 | +Place the resulting library in the same directory as the existing |
| 35 | +static libpythonX.Y.a and relink plpython. |
45 | 36 |
|
46 | | - 5) 'psql -Upostgres yourTESTdb < plpython_create.sql' |
47 | 37 |
|
48 | | -*** USING *** |
49 | | - |
50 | | - There are sample functions in 'plpython_function.sql'. |
51 | | -Remember that the python code you write gets transformed into a |
52 | | -function. ie. |
53 | | - |
54 | | -CREATE FUNCTION myfunc(text) RETURNS text |
55 | | - AS |
56 | | -'return args[0]' |
57 | | - LANGUAGE 'plpython'; |
58 | | - |
59 | | -gets tranformed into |
60 | | - |
61 | | -def __plpython_procedure_myfunc_23456(): |
62 | | - return args[0] |
63 | | - |
64 | | -where 23456 is the Oid of the function. |
65 | | - |
66 | | -If you don't provide a return value, python returns the default 'None' |
67 | | -which probably isn't what you want. The language module transforms |
68 | | -python None to postgresql NULL. |
69 | | - |
70 | | -Postgresql function variables are available in the global "args" list. |
71 | | -In the myfunc example, args[0] contains whatever was passed in as the |
72 | | -text argument. For myfunc2(text, int4), args[0] would contain the |
73 | | -text variable and args[1] the int4 variable. The global dictionary SD |
74 | | -is available to store data between function calls. This variable is |
75 | | -private static data. The global dictionary GD is public data, |
76 | | -available to all python functions within a backend. Use with care. |
77 | | -When the function is used in a trigger, the triggers tuples are in |
78 | | -TD["new"] and/or TD["old"] depending on the trigger event. Return |
79 | | -'None' or "OK" from the python function to indicate the tuple is |
80 | | -unmodified, "SKIP" to abort the event, or "MODIFIED" to indicate |
81 | | -you've modified the tuple. If the trigger was called with arguments |
82 | | -they are available in TD["args"][0] to TD["args"][(n -1)] |
83 | | - |
84 | | -Each function gets it's own restricted execution object in the python |
85 | | -interpreter so global data, function arguments from myfunc are not |
86 | | -available to myfunc2. Except for data in the GD dictionary, as |
87 | | -mentioned above. |
88 | | - |
89 | | -The plpython language module automatically imports a python module |
90 | | -called 'plpy'. The functions and constants in this module are |
91 | | -available to you in the python code as 'plpy.foo'. At present 'plpy' |
92 | | -implements the functions 'plpy.error("msg")', 'plpy.fatal("msg")', |
93 | | -'plpy.debug("msg")' and 'plpy.notice("msg")'. They are mostly |
94 | | -equivalent to calling 'elog(LEVEL, "msg")', where level is DEBUG, |
95 | | -ERROR, FATAL or NOTICE. 'plpy.error', and 'plpy.fatal' actually raise |
96 | | -a python exception which if uncaught causes the plpython module to |
97 | | -call elog(ERROR, msg) when the function handler returns from the |
98 | | -python interpreter. Long jumping out of the python interpreter |
99 | | -probably isn't good. 'raise plpy.ERROR("msg")' and 'raise |
100 | | -plpy.FATAL("msg") are equivalent to calling plpy.error or plpy.fatal. |
101 | | - |
102 | | -Additionally the in the plpy module there are two functions called |
103 | | -execute and prepare. Calling plpy.execute with a query string, and |
104 | | -optional limit argument, causing that query to be run, and the result |
105 | | -returned in a result object. The result object emulates a list or |
106 | | -dictionary objects. The result object can be accessed by row number, |
107 | | -and field name. It has these additional methods: nrows() which |
108 | | -returns the number of rows returned by the query, and status which is |
109 | | -the SPI_exec return variable. The result object can be modified. |
110 | | - |
111 | | -rv = plpy.execute("SELECT * FROM my_table", 5) |
112 | | - |
113 | | -returns up to 5 rows from my_table. if my_table a column my_field it |
114 | | -would be accessed as |
115 | | - |
116 | | -foo = rv[i]["my_field"] |
117 | | - |
118 | | -The second function plpy.prepare is called with a query string, and a |
119 | | -list of argument types if you have bind variables in the query. |
120 | | - |
121 | | -plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = |
122 | | -$1", [ "text" ]) |
123 | | - |
124 | | -text is the type of the variable you will be passing as $1. After |
125 | | -preparing you use the function plpy.execute to run it. |
126 | | - |
127 | | -rv = plpy.execute(plan, [ "name" ], 5) |
128 | | - |
129 | | -The limit argument is optional in the call to plpy.execute. |
130 | | - |
131 | | -When you prepare a plan using the plpython module it is automatically |
132 | | -saved. Read the SPI documentation for postgresql for a description of |
133 | | -what this means. Anyway the take home message is if you do: |
134 | | - |
135 | | -plan = plpy.prepare("SOME QUERY") |
136 | | -plan = plpy.prepare("SOME OTHER QUERY") |
137 | | - |
138 | | -You are leaking memory, as I know of no way to free a saved plan. The |
139 | | -alternative of using unsaved plans it even more painful (for me). |
140 | | - |
141 | | -*** BUGS *** |
142 | | - |
143 | | -If the module blows up postgresql or bites your dog, please send a |
144 | | -script that will recreate the behaviour. Back traces from core dumps |
145 | | -are good, but python reference counting bugs and postgresql exeception |
146 | | -handling bugs give uninformative back traces (you can't long_jmp into |
147 | | -functions that have already returned? *boggle*) |
148 | | - |
149 | | -*** TODO *** |
150 | | - |
151 | | -1) create a new restricted execution class that will allow me to pass |
152 | | -function arguments in as locals. passing them as globals means |
153 | | -function cannot be called recursively... |
154 | | - |
155 | | -2) Functions cache the input and output functions for their arguments, |
156 | | -so the following will make postgres unhappy |
157 | | - |
158 | | -create table users (first_name text, last_name text); |
159 | | -create function user_name(user) returns text as 'mycode' language 'plpython'; |
160 | | -select user_name(user) from users; |
161 | | -alter table add column user_id int4; |
162 | | -select user_name(user) from users; |
163 | | - |
164 | | -you have to drop and create the function(s) each time it's arguments |
165 | | -are modified (not nice), don't cache the input and output functions |
166 | | -(slower?), or check if the structure of the argument has been altered |
167 | | -(is this possible, easy, quick?) and recreate cache. |
168 | | - |
169 | | -3) better documentation |
170 | | - |
171 | | -4) suggestions? |
| 38 | +Further documentation is available in the PostgreSQL Programmer's |
| 39 | +Guide. |
0 commit comments