Commit 61152244 authored by Tom Lane's avatar Tom Lane

Rename plpython to plpythonu, and update documentation to reflect its

now-untrusted status.
parent 219e2978
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/plpython.sgml,v 1.16 2003/04/07 01:29:25 petere Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/plpython.sgml,v 1.17 2003/06/30 18:31:41 tgl Exp $ -->
<chapter id="plpython"> <chapter id="plpython">
<title>PL/Python - Python Procedural Language</title> <title>PL/Python - Python Procedural Language</title>
...@@ -14,9 +14,21 @@ ...@@ -14,9 +14,21 @@
<para> <para>
To install PL/Python in a particular database, use To install PL/Python in a particular database, use
<literal>createlang plpython <replaceable>dbname</></literal>. <literal>createlang plpythonu <replaceable>dbname</></literal>.
</para> </para>
<note>
<para>
As of <productname>PostgreSQL</productname> 7.4,
PL/Python is only available as an <quote>untrusted</> language
(meaning it does not offer any way of restricting what users
can do in it). It has therefore been renamed to <literal>plpythonu</>.
The trusted variant <literal>plpython</> may become available again in
future, if a new secure execution mechanism is developed by the Python
community.
</para>
</note>
<tip> <tip>
<para> <para>
If a language is installed into <literal>template1</>, all subsequently If a language is installed into <literal>template1</>, all subsequently
...@@ -41,7 +53,7 @@ ...@@ -41,7 +53,7 @@
<programlisting> <programlisting>
CREATE FUNCTION myfunc(text) RETURNS text CREATE FUNCTION myfunc(text) RETURNS text
AS 'return args[0]' AS 'return args[0]'
LANGUAGE plpython; LANGUAGE plpythonu;
</programlisting> </programlisting>
gets transformed into gets transformed into
...@@ -78,6 +90,8 @@ def __plpython_procedure_myfunc_23456(): ...@@ -78,6 +90,8 @@ def __plpython_procedure_myfunc_23456():
available to all Python functions within a session. Use with care. available to all Python functions within a session. Use with care.
</para> </para>
<!-- NOT CORRECT ANYMORE, IS IT?
<para> <para>
Each function gets its own restricted execution object in the Each function gets its own restricted execution object in the
Python interpreter, so that global data and function arguments from Python interpreter, so that global data and function arguments from
...@@ -85,6 +99,9 @@ def __plpython_procedure_myfunc_23456(): ...@@ -85,6 +99,9 @@ def __plpython_procedure_myfunc_23456():
<function>myfunc2</function>. The exception is the data in the <function>myfunc2</function>. The exception is the data in the
<varname>GD</varname> dictionary, as mentioned above. <varname>GD</varname> dictionary, as mentioned above.
</para> </para>
-->
</sect1> </sect1>
<sect1 id="plpython-trigger"> <sect1 id="plpython-trigger">
...@@ -218,11 +235,13 @@ CREATE FUNCTION usesavedplan() RETURNS trigger AS ' ...@@ -218,11 +235,13 @@ CREATE FUNCTION usesavedplan() RETURNS trigger AS '
plan = plpy.prepare("SELECT 1") plan = plpy.prepare("SELECT 1")
SD["plan"] = plan SD["plan"] = plan
# rest of function # rest of function
' LANGUAGE plpython; ' LANGUAGE plpythonu;
</programlisting> </programlisting>
</para> </para>
</sect1> </sect1>
<!-- NOT CURRENTLY SUPPORTED
<sect1 id="plpython-trusted"> <sect1 id="plpython-trusted">
<title>Restricted Environment</title> <title>Restricted Environment</title>
...@@ -245,4 +264,6 @@ CREATE FUNCTION usesavedplan() RETURNS trigger AS ' ...@@ -245,4 +264,6 @@ CREATE FUNCTION usesavedplan() RETURNS trigger AS '
</para> </para>
</sect1> </sect1>
-->
</chapter> </chapter>
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.195 2003/06/28 00:12:40 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.196 2003/06/30 18:31:41 tgl Exp $
--> -->
<appendix id="release"> <appendix id="release">
...@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without ...@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters. worries about funny characters.
--> -->
<literallayout><![CDATA[ <literallayout><![CDATA[
PL/Python is now an untrusted language, and is renamed to 'plpythonu'
Dollar sign ($) is no longer allowed in operator names Dollar sign ($) is no longer allowed in operator names
Dollar sign ($) can be a non-first character in identifiers Dollar sign ($) can be a non-first character in identifiers
Precision in FLOAT(p) is now interpreted as bits, not decimal digits Precision in FLOAT(p) is now interpreted as bits, not decimal digits
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/xplang.sgml,v 1.21 2003/04/07 01:29:26 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/xplang.sgml,v 1.22 2003/06/30 18:31:42 tgl Exp $
--> -->
<chapter id="xplang"> <chapter id="xplang">
...@@ -109,13 +109,14 @@ CREATE <optional>TRUSTED</optional> <optional>PROCEDURAL</optional> LANGUAGE <re ...@@ -109,13 +109,14 @@ CREATE <optional>TRUSTED</optional> <optional>PROCEDURAL</optional> LANGUAGE <re
for languages that do not allow access to database server for languages that do not allow access to database server
internals or the file system. The languages internals or the file system. The languages
<application>PL/pgSQL</application>, <application>PL/pgSQL</application>,
<application>PL/Tcl</application>, <application>PL/Tcl</application>, and
<application>PL/Perl</application>, and <application>PL/Perl</application>
<application>PL/Python</application> are known to be trusted; are considered trusted; the languages
the languages <application>PL/TclU</application> and <application>PL/TclU</application>,
<application>PL/PerlU</application> are designed to provide <application>PL/PerlU</application>, and
unlimited functionality and should <emphasis>not</emphasis> be <application>PL/PythonU</application>
marked trusted. are designed to provide unlimited functionality and should
<emphasis>not</emphasis> be marked trusted.
</para> </para>
</step> </step>
</procedure> </procedure>
...@@ -158,7 +159,7 @@ CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql ...@@ -158,7 +159,7 @@ CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
directory. If <application>Tcl/Tk</> support is configured in, the handlers for directory. If <application>Tcl/Tk</> support is configured in, the handlers for
<application>PL/Tcl</> and <application>PL/TclU</> are also built and installed in the same <application>PL/Tcl</> and <application>PL/TclU</> are also built and installed in the same
location. Likewise, the <application>PL/Perl</> and <application>PL/PerlU</> handlers are built location. Likewise, the <application>PL/Perl</> and <application>PL/PerlU</> handlers are built
and installed if Perl support is configured, and <application>PL/Python</> is and installed if Perl support is configured, and <application>PL/PythonU</> is
installed if Python support is configured. installed if Python support is configured.
</para> </para>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/bin/scripts/createlang.c,v 1.3 2003/06/11 05:13:12 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/scripts/createlang.c,v 1.4 2003/06/30 18:31:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -195,16 +195,16 @@ main(int argc, char *argv[]) ...@@ -195,16 +195,16 @@ main(int argc, char *argv[])
handler = "plperl_call_handler"; handler = "plperl_call_handler";
object = "plperl"; object = "plperl";
} }
else if (strcmp(langname, "plpython")==0) else if (strcmp(langname, "plpythonu")==0)
{ {
trusted = true; trusted = false;
handler = "plpython_call_handler"; handler = "plpython_call_handler";
object = "plpython"; object = "plpython";
} }
else else
{ {
fprintf(stderr, _("%s: unsupported language \"%s\"\n"), progname, langname); fprintf(stderr, _("%s: unsupported language \"%s\"\n"), progname, langname);
fprintf(stderr, _("Supported languages are plpgsql, pltcl, pltclu, plperl, plperlu, and plpython.\n")); fprintf(stderr, _("Supported languages are plpgsql, pltcl, pltclu, plperl, plperlu, and plpythonu.\n"));
exit(1); exit(1);
} }
......
PL/Python - Python Procedural Language for PostgreSQL
-----------------------------------------------------
$Id: README,v 1.2 2001/05/14 22:06:50 petere Exp $
Installation:
configure --with-python
cd src/pl/plpython
gmake
gmake install
Test:
# have postmaster running...
gmake installcheck
Enable language:
createlang plpython dbname
Note that PL/Python is currently not built automatically because the
code is new and there are some portability issues.
A default Python installation does not provide a shared libpython
library. This is not a problem on many platforms (although it makes
things less efficient), but on some platforms (especially HP-UX) the
link will fail outright.
To create a shared libpython, see this web page for hints:
http://www.python.org/cgi-bin/faqw.py?req=show&file=faq03.030.htp
Place the resulting library in the same directory as the existing
static libpythonX.Y.a and relink plpython.
Further documentation is available in the PostgreSQL Programmer's
Guide.
In no particular order... In no particular order...
* Develop a trusted variant of PL/Python. Now that RExec has been shown
to be full of holes, this may take a while :-(
* Allow arrays as function arguments and return values. (almost done) * Allow arrays as function arguments and return values. (almost done)
* Create a new restricted execution class that will allow me to pass * Create a new restricted execution class that will allow me to pass
...@@ -10,7 +13,7 @@ In no particular order... ...@@ -10,7 +13,7 @@ In no particular order...
so the following will make PostgreSQL unhappy: so the following will make PostgreSQL unhappy:
create table users (first_name text, last_name text); create table users (first_name text, last_name text);
create function user_name(user) returns text as 'mycode' language 'plpython'; create function user_name(user) returns text as 'mycode' language plpython;
select user_name(user) from users; select user_name(user) from users;
alter table add column user_id integer; alter table add column user_id integer;
select user_name(user) from users; select user_name(user) from users;
......
...@@ -16,24 +16,15 @@ SELECT valid_type('rick'); ...@@ -16,24 +16,15 @@ SELECT valid_type('rick');
(1 row) (1 row)
SELECT read_file('/etc/passwd'); SELECT write_file('/tmp/plpython','Only trusted users should be able to do this!');
ERROR: plpython: Call of function `read_file' failed. write_file
exceptions.IOError: can't open files in restricted mode ------------------------------
SELECT write_file('/tmp/plpython','This is very bad'); Wrote to file: /tmp/plpython
ERROR: plpython: Call of function `write_file' failed. (1 row)
exceptions.IOError: can't open files in restricted mode
SELECT getpid(); SELECT read_file('/tmp/plpython');
ERROR: plpython: Call of function `getpid' failed. read_file
exceptions.AttributeError: 'module' object has no attribute 'getpid' -----------------------------------------------
SELECT uname(); Only trusted users should be able to do this!
ERROR: plpython: Call of function `uname' failed.
exceptions.AttributeError: 'module' object has no attribute 'uname'
SELECT sys_exit();
ERROR: plpython: Call of function `sys_exit' failed.
exceptions.AttributeError: 'module' object has no attribute 'exit'
SELECT sys_argv();
sys_argv
----------------
['RESTRICTED']
(1 row) (1 row)
...@@ -29,7 +29,7 @@ SELECT global_test_two(); ...@@ -29,7 +29,7 @@ SELECT global_test_two();
(1 row) (1 row)
SELECT import_fail(); SELECT import_fail();
NOTICE: ('import socket failed -- untrusted dynamic module: _socket',) NOTICE: ('import socket failed -- No module named foosocket',)
import_fail import_fail
-------------------- --------------------
failed as expected failed as expected
......
...@@ -7,5 +7,5 @@ DROP TRIGGER users_update_trig on users ; ...@@ -7,5 +7,5 @@ DROP TRIGGER users_update_trig on users ;
DROP FUNCTION users_update() ; DROP FUNCTION users_update() ;
DROP TRIGGER users_delete_trig on users ; DROP TRIGGER users_delete_trig on users ;
DROP FUNCTION users_delete() ; DROP FUNCTION users_delete() ;
DROP PROCEDURAL LANGUAGE 'plpython' ; DROP PROCEDURAL LANGUAGE plpythonu ;
DROP FUNCTION plpython_call_handler() ; DROP FUNCTION plpython_call_handler() ;
...@@ -7,7 +7,7 @@ CREATE FUNCTION global_test_one() returns text ...@@ -7,7 +7,7 @@ CREATE FUNCTION global_test_one() returns text
if not GD.has_key("global_test"): if not GD.has_key("global_test"):
GD["global_test"] = "set by global_test_one" GD["global_test"] = "set by global_test_one"
return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]' return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION global_test_two() returns text CREATE FUNCTION global_test_two() returns text
AS AS
...@@ -16,7 +16,7 @@ CREATE FUNCTION global_test_two() returns text ...@@ -16,7 +16,7 @@ CREATE FUNCTION global_test_two() returns text
if not GD.has_key("global_test"): if not GD.has_key("global_test"):
GD["global_test"] = "set by global_test_two" GD["global_test"] = "set by global_test_two"
return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]' return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION static_test() returns int4 CREATE FUNCTION static_test() returns int4
...@@ -27,7 +27,7 @@ else: ...@@ -27,7 +27,7 @@ else:
SD["call"] = 1 SD["call"] = 1
return SD["call"] return SD["call"]
' '
LANGUAGE 'plpython'; LANGUAGE plpythonu;
-- import python modules -- import python modules
...@@ -39,7 +39,7 @@ except Exception, ex: ...@@ -39,7 +39,7 @@ except Exception, ex:
plpy.notice("import socket failed -- %s" % str(ex)) plpy.notice("import socket failed -- %s" % str(ex))
return "failed as expected" return "failed as expected"
return "succeeded, that wasn''t supposed to happen"' return "succeeded, that wasn''t supposed to happen"'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION import_succeed() returns text CREATE FUNCTION import_succeed() returns text
...@@ -63,14 +63,14 @@ except Exception, ex: ...@@ -63,14 +63,14 @@ except Exception, ex:
plpy.notice("import failed -- %s" % str(ex)) plpy.notice("import failed -- %s" % str(ex))
return "failed, that wasn''t supposed to happen" return "failed, that wasn''t supposed to happen"
return "succeeded, as expected"' return "succeeded, as expected"'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION import_test_one(text) RETURNS text CREATE FUNCTION import_test_one(text) RETURNS text
AS AS
'import sha 'import sha
digest = sha.new(args[0]) digest = sha.new(args[0])
return digest.hexdigest()' return digest.hexdigest()'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION import_test_two(users) RETURNS text CREATE FUNCTION import_test_two(users) RETURNS text
AS AS
...@@ -78,7 +78,7 @@ CREATE FUNCTION import_test_two(users) RETURNS text ...@@ -78,7 +78,7 @@ CREATE FUNCTION import_test_two(users) RETURNS text
plain = args[0]["fname"] + args[0]["lname"] plain = args[0]["fname"] + args[0]["lname"]
digest = sha.new(plain); digest = sha.new(plain);
return "sha hash of " + plain + " is " + digest.hexdigest()' return "sha hash of " + plain + " is " + digest.hexdigest()'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION argument_test_one(users, text, text) RETURNS text CREATE FUNCTION argument_test_one(users, text, text) RETURNS text
AS AS
...@@ -89,7 +89,7 @@ for key in keys: ...@@ -89,7 +89,7 @@ for key in keys:
out.append("%s: %s" % (key, args[0][key])) out.append("%s: %s" % (key, args[0][key]))
words = args[1] + " " + args[2] + " => {" + ", ".join(out) + "}" words = args[1] + " " + args[2] + " => {" + ", ".join(out) + "}"
return words' return words'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
-- these triggers are dedicated to HPHC of RI who -- these triggers are dedicated to HPHC of RI who
...@@ -110,7 +110,7 @@ if TD["new"]["fname"] == "william": ...@@ -110,7 +110,7 @@ if TD["new"]["fname"] == "william":
TD["new"]["fname"] = TD["args"][0] TD["new"]["fname"] = TD["args"][0]
rv = "MODIFY" rv = "MODIFY"
return rv' return rv'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION users_update() returns trigger CREATE FUNCTION users_update() returns trigger
...@@ -119,7 +119,7 @@ CREATE FUNCTION users_update() returns trigger ...@@ -119,7 +119,7 @@ CREATE FUNCTION users_update() returns trigger
if TD["old"]["fname"] != TD["new"]["fname"] and TD["old"]["fname"] == TD["args"][0]: if TD["old"]["fname"] != TD["new"]["fname"] and TD["old"]["fname"] == TD["args"][0]:
return "SKIP" return "SKIP"
return None' return None'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION users_delete() RETURNS trigger CREATE FUNCTION users_delete() RETURNS trigger
...@@ -127,7 +127,7 @@ CREATE FUNCTION users_delete() RETURNS trigger ...@@ -127,7 +127,7 @@ CREATE FUNCTION users_delete() RETURNS trigger
'if TD["old"]["fname"] == TD["args"][0]: 'if TD["old"]["fname"] == TD["args"][0]:
return "SKIP" return "SKIP"
return None' return None'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE TRIGGER users_insert_trig BEFORE INSERT ON users FOR EACH ROW CREATE TRIGGER users_insert_trig BEFORE INSERT ON users FOR EACH ROW
...@@ -148,19 +148,19 @@ CREATE FUNCTION nested_call_one(text) RETURNS text ...@@ -148,19 +148,19 @@ CREATE FUNCTION nested_call_one(text) RETURNS text
'q = "SELECT nested_call_two(''%s'')" % args[0] 'q = "SELECT nested_call_two(''%s'')" % args[0]
r = plpy.execute(q) r = plpy.execute(q)
return r[0]' return r[0]'
LANGUAGE 'plpython' ; LANGUAGE plpythonu ;
CREATE FUNCTION nested_call_two(text) RETURNS text CREATE FUNCTION nested_call_two(text) RETURNS text
AS AS
'q = "SELECT nested_call_three(''%s'')" % args[0] 'q = "SELECT nested_call_three(''%s'')" % args[0]
r = plpy.execute(q) r = plpy.execute(q)
return r[0]' return r[0]'
LANGUAGE 'plpython' ; LANGUAGE plpythonu ;
CREATE FUNCTION nested_call_three(text) RETURNS text CREATE FUNCTION nested_call_three(text) RETURNS text
AS AS
'return args[0]' 'return args[0]'
LANGUAGE 'plpython' ; LANGUAGE plpythonu ;
-- some spi stuff -- some spi stuff
...@@ -176,7 +176,7 @@ except Exception, ex: ...@@ -176,7 +176,7 @@ except Exception, ex:
plpy.error(str(ex)) plpy.error(str(ex))
return None return None
' '
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION spi_prepared_plan_test_nested(text) RETURNS text CREATE FUNCTION spi_prepared_plan_test_nested(text) RETURNS text
AS AS
...@@ -191,12 +191,12 @@ except Exception, ex: ...@@ -191,12 +191,12 @@ except Exception, ex:
plpy.error(str(ex)) plpy.error(str(ex))
return None return None
' '
LANGUAGE 'plpython'; LANGUAGE plpythonu;
/* really stupid function just to get the module loaded /* really stupid function just to get the module loaded
*/ */
CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE 'plpython'; CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE plpythonu;
/* a typo /* a typo
*/ */
...@@ -210,7 +210,7 @@ if len(rv): ...@@ -210,7 +210,7 @@ if len(rv):
return rv[0]["fname"] return rv[0]["fname"]
return None return None
' '
LANGUAGE 'plpython'; LANGUAGE plpythonu;
/* for what it's worth catch the exception generated by /* for what it's worth catch the exception generated by
* the typo, and return None * the typo, and return None
...@@ -229,7 +229,7 @@ if len(rv): ...@@ -229,7 +229,7 @@ if len(rv):
return rv[0]["fname"] return rv[0]["fname"]
return None return None
' '
LANGUAGE 'plpython'; LANGUAGE plpythonu;
/* for what it's worth catch the exception generated by /* for what it's worth catch the exception generated by
* the typo, and reraise it as a plain error * the typo, and reraise it as a plain error
...@@ -247,7 +247,7 @@ if len(rv): ...@@ -247,7 +247,7 @@ if len(rv):
return rv[0]["fname"] return rv[0]["fname"]
return None return None
' '
LANGUAGE 'plpython'; LANGUAGE plpythonu;
/* no typo no messing about /* no typo no messing about
...@@ -261,20 +261,20 @@ if len(rv): ...@@ -261,20 +261,20 @@ if len(rv):
return rv[0]["fname"] return rv[0]["fname"]
return None return None
' '
LANGUAGE 'plpython'; LANGUAGE plpythonu;
/* Flat out syntax error /* Flat out syntax error
*/ */
CREATE FUNCTION sql_syntax_error() RETURNS text CREATE FUNCTION sql_syntax_error() RETURNS text
AS AS
'plpy.execute("syntax error")' 'plpy.execute("syntax error")'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
/* check the handling of uncaught python exceptions /* check the handling of uncaught python exceptions
*/ */
CREATE FUNCTION exception_index_invalid(text) RETURNS text CREATE FUNCTION exception_index_invalid(text) RETURNS text
AS AS
'return args[1]' 'return args[1]'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
/* check handling of nested exceptions /* check handling of nested exceptions
*/ */
...@@ -282,7 +282,7 @@ CREATE FUNCTION exception_index_invalid_nested() RETURNS text ...@@ -282,7 +282,7 @@ CREATE FUNCTION exception_index_invalid_nested() RETURNS text
AS AS
'rv = plpy.execute("SELECT test5(''foo'')") 'rv = plpy.execute("SELECT test5(''foo'')")
return rv[0]' return rv[0]'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE FUNCTION join_sequences(sequences) RETURNS text CREATE FUNCTION join_sequences(sequences) RETURNS text
...@@ -296,13 +296,13 @@ for r in rv: ...@@ -296,13 +296,13 @@ for r in rv:
seq = seq + r["sequence"] seq = seq + r["sequence"]
return seq return seq
' '
LANGUAGE 'plpython'; LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION read_file(text) RETURNS text AS ' CREATE OR REPLACE FUNCTION read_file(text) RETURNS text AS '
return open(args[0]).read() return open(args[0]).read()
' LANGUAGE 'plpython'; ' LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION write_file(text,text) RETURNS text AS ' CREATE OR REPLACE FUNCTION write_file(text,text) RETURNS text AS '
open(args[0],"w").write(args[1]) open(args[0],"w").write(args[1])
return "Wrote to file: %s" % args[0] return "Wrote to file: %s" % args[0]
' LANGUAGE 'plpython'; ' LANGUAGE plpythonu;
...@@ -8,4 +8,4 @@ CREATE FUNCTION test_setof() returns setof text ...@@ -8,4 +8,4 @@ CREATE FUNCTION test_setof() returns setof text
else: else:
GD["calls"] = 1 GD["calls"] = 1
return str(GD["calls"])' return str(GD["calls"])'
LANGUAGE 'plpython'; LANGUAGE plpythonu;
...@@ -11,7 +11,7 @@ createdb $DBNAME >> test.log 2>&1 ...@@ -11,7 +11,7 @@ createdb $DBNAME >> test.log 2>&1
echo " Done. ***" echo " Done. ***"
echo -n "*** Create plpython." echo -n "*** Create plpython."
createlang plpython $DBNAME >> test.log 2>&1 createlang plpythonu $DBNAME >> test.log 2>&1
echo " Done. ***" echo " Done. ***"
echo -n "*** Create tables" echo -n "*** Create tables"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment