Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
1ca717f3
Commit
1ca717f3
authored
Nov 16, 2001
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
plpython security and error handling fixes, from
Kevin Jacobs and Brad McLean.
parent
b0df7a60
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
272 additions
and
57 deletions
+272
-57
src/pl/plpython/error.expected
src/pl/plpython/error.expected
+26
-9
src/pl/plpython/plpython.c
src/pl/plpython/plpython.c
+200
-47
src/pl/plpython/plpython_error.sql
src/pl/plpython/plpython_error.sql
+8
-0
src/pl/plpython/plpython_function.sql
src/pl/plpython/plpython_function.sql
+38
-1
No files found.
src/pl/plpython/error.expected
View file @
1ca717f3
SELECT invalid_type_uncaught('rick');
ERROR: plpython: Call of function `__plpython_procedure_invalid_type_uncaught_1175341' failed.
NOTICE: plpython: in function __plpython_procedure_invalid_type_uncaught_49801:
plpy.SPIError: Cache lookup for type `test' failed.
SELECT invalid_type_caught('rick');
NOTICE: ("Cache lookup for type `test' failed.",)
invalid_type_caught
---------------------
(1 row)
NOTICE: plpython: in function __plpython_procedure_invalid_type_caught_49802:
plpy.SPIError: Cache lookup for type `test' failed.
SELECT invalid_type_reraised('rick');
ERROR: plpython: Call of function `__plpython_procedure_invalid_type_reraised_1175343' failed.
plpy.
Error: ("Cache lookup for type `test' failed.",)
NOTICE: plpython: in function __plpython_procedure_invalid_type_reraised_49803:
plpy.
SPIError: Cache lookup for type `test' failed.
SELECT valid_type('rick');
valid_type
------------
(1 row)
SELECT read_file('/etc/passwd');
ERROR: plpython: Call of function `__plpython_procedure_read_file_49809' failed.
exceptions.IOError: can't open files in restricted mode
SELECT write_file('/tmp/plpython','This is very bad');
ERROR: plpython: Call of function `__plpython_procedure_write_file_49810' failed.
exceptions.IOError: can't open files in restricted mode
SELECT getpid();
ERROR: plpython: Call of function `__plpython_procedure_getpid_49811' failed.
exceptions.AttributeError: getpid
SELECT uname();
ERROR: plpython: Call of function `__plpython_procedure_uname_49812' failed.
exceptions.AttributeError: uname
SELECT sys_exit();
ERROR: plpython: Call of function `__plpython_procedure_sys_exit_49813' failed.
exceptions.AttributeError: exit
SELECT sys_argv();
sys_argv
----------------
['RESTRICTED']
(1 row)
src/pl/plpython/plpython.c
View file @
1ca717f3
...
...
@@ -29,7 +29,7 @@
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.1
2 2001/11/05 17:46:39 momjian
Exp $
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.1
3 2001/11/16 18:04:31 tgl
Exp $
*
*********************************************************************
*/
...
...
@@ -188,6 +188,10 @@ static void PLy_init_interp(void);
static
void
PLy_init_safe_interp
(
void
);
static
void
PLy_init_plpy
(
void
);
/* Helper functions used during initialization */
static
int
populate_methods
(
PyObject
*
klass
,
PyMethodDef
*
methods
);
static
PyObject
*
build_tuple
(
char
*
string_list
[],
int
len
);
/* error handler. collects the current Python exception, if any,
* and appends it to the error and sends it to elog
*/
...
...
@@ -199,6 +203,10 @@ static void
PLy_exception_set
(
PyObject
*
,
const
char
*
,...)
__attribute__
((
format
(
printf
,
2
,
3
)));
/* Get the innermost python procedure called from the backend.
*/
static
char
*
PLy_procedure_name
(
PLyProcedure
*
);
/* some utility functions
*/
static
void
*
PLy_malloc
(
size_t
);
...
...
@@ -240,6 +248,10 @@ static void PLy_input_datum_func2(PLyDatumToOb *, Form_pg_type);
static
void
PLy_output_tuple_funcs
(
PLyTypeInfo
*
,
TupleDesc
);
static
void
PLy_input_tuple_funcs
(
PLyTypeInfo
*
,
TupleDesc
);
/* RExec methods
*/
static
PyObject
*
PLy_r_open
(
PyObject
*
self
,
PyObject
*
args
);
/* conversion functions
*/
static
PyObject
*
PLyDict_FromTuple
(
PLyTypeInfo
*
,
HeapTuple
,
TupleDesc
);
...
...
@@ -255,6 +267,11 @@ static PyObject *PLyString_FromString(const char *);
static
int
PLy_first_call
=
1
;
static
volatile
int
PLy_call_level
=
0
;
/*
* Last function called by postgres backend
*/
static
PLyProcedure
*
PLy_last_procedure
=
NULL
;
/* this gets modified in plpython_call_handler and PLy_elog.
* test it any old where, but do NOT modify it anywhere except
* those two functions
...
...
@@ -265,35 +282,60 @@ static PyObject *PLy_interp_globals = NULL;
static
PyObject
*
PLy_interp_safe
=
NULL
;
static
PyObject
*
PLy_interp_safe_globals
=
NULL
;
static
PyObject
*
PLy_importable_modules
=
NULL
;
static
PyObject
*
PLy_ok_posix_names
=
NULL
;
static
PyObject
*
PLy_ok_sys_names
=
NULL
;
static
PyObject
*
PLy_procedure_cache
=
NULL
;
char
*
PLy_importable_modules_list
[]
=
{
static
char
*
PLy_importable_modules_list
[]
=
{
"array"
,
"bisect"
,
"binascii"
,
"calendar"
,
"cmath"
,
"codecs"
,
"errno"
,
"marshal"
,
"math"
,
"md5"
,
"mpz"
,
"operator"
,
"pcre"
,
"pickle"
,
"random"
,
"re"
,
"regex"
,
"sre"
,
"sha"
,
"string"
,
"StringIO"
,
"struct"
,
"time"
,
"whrandom"
,
"zlib"
};
static
char
*
PLy_ok_posix_names_list
[]
=
{
/* None for now */
};
static
char
*
PLy_ok_sys_names_list
[]
=
{
"byteeorder"
,
"copyright"
,
"getdefaultencoding"
,
"getrefcount"
,
"hexrevision"
,
"maxint"
,
"maxunicode"
,
"platform"
,
"version"
,
"version_info"
};
/* Python exceptions
*/
PyObject
*
PLy_exc_error
=
NULL
;
PyObject
*
PLy_exc_fatal
=
NULL
;
PyObject
*
PLy_exc_spi_error
=
NULL
;
static
PyObject
*
PLy_exc_error
=
NULL
;
static
PyObject
*
PLy_exc_fatal
=
NULL
;
static
PyObject
*
PLy_exc_spi_error
=
NULL
;
/* some globals for the python module
*/
...
...
@@ -334,7 +376,6 @@ perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
fmgr_info_cxt
(
functionId
,
finfo
,
TopMemoryContext
);
}
Datum
plpython_call_handler
(
PG_FUNCTION_ARGS
)
{
...
...
@@ -366,8 +407,10 @@ plpython_call_handler(PG_FUNCTION_ARGS)
}
else
PLy_restart_in_progress
+=
1
;
if
(
proc
)
if
(
proc
)
{
Py_DECREF
(
proc
->
me
);
}
RERAISE_EXC
();
}
...
...
@@ -805,7 +848,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
if
(
plrv
==
NULL
)
{
elog
(
FATAL
,
"Aiieee, PLy_procedure_call returned NULL"
);
#if
0
#if
def NOT_USED
if
(
!
PLy_restart_in_progress
)
PLy_elog
(
ERROR
,
"plpython: Function
\"
%s
\"
failed."
,
proc
->
proname
);
...
...
@@ -853,11 +896,15 @@ PyObject *
PLy_procedure_call
(
PLyProcedure
*
proc
,
char
*
kargs
,
PyObject
*
vargs
)
{
PyObject
*
rv
;
PLyProcedure
*
current
;
enter
();
current
=
PLy_last_procedure
;
PLy_last_procedure
=
proc
;
PyDict_SetItemString
(
proc
->
globals
,
kargs
,
vargs
);
rv
=
PyObject_CallFunction
(
proc
->
reval
,
"O"
,
proc
->
code
);
PLy_last_procedure
=
current
;
if
((
rv
==
NULL
)
||
(
PyErr_Occurred
()))
{
...
...
@@ -1150,12 +1197,6 @@ PLy_procedure_compile(PLyProcedure * proc, const char *src)
if
((
proc
->
interp
==
NULL
)
||
(
PyErr_Occurred
()))
PLy_elog
(
ERROR
,
"Unable to create rexec.RExec instance"
);
/*
* tweak the list of permitted modules
*/
PyObject_SetAttrString
(
proc
->
interp
,
"ok_builtin_modules"
,
PLy_importable_modules
);
proc
->
reval
=
PyObject_GetAttrString
(
proc
->
interp
,
"r_eval"
);
if
((
proc
->
reval
==
NULL
)
||
(
PyErr_Occurred
()))
PLy_elog
(
ERROR
,
"Unable to get method `r_eval' from rexec.RExec"
);
...
...
@@ -1632,9 +1673,12 @@ static PyObject *PLy_plan_status(PyObject *, PyObject *);
static
PyObject
*
PLy_result_new
(
void
);
static
void
PLy_result_dealloc
(
PyObject
*
);
static
PyObject
*
PLy_result_getattr
(
PyObject
*
,
char
*
);
#ifdef NOT_USED
/* Appear to be unused */
static
PyObject
*
PLy_result_fetch
(
PyObject
*
,
PyObject
*
);
static
PyObject
*
PLy_result_nrows
(
PyObject
*
,
PyObject
*
);
static
PyObject
*
PLy_result_status
(
PyObject
*
,
PyObject
*
);
#endif
static
int
PLy_result_length
(
PyObject
*
);
static
PyObject
*
PLy_result_item
(
PyObject
*
,
int
);
static
PyObject
*
PLy_result_slice
(
PyObject
*
,
int
,
int
);
...
...
@@ -1650,7 +1694,7 @@ static PyObject *PLy_spi_execute_plan(PyObject *, PyObject *, int);
static
PyObject
*
PLy_spi_execute_fetch_result
(
SPITupleTable
*
,
int
,
int
);
PyTypeObject
PLy_PlanType
=
{
static
PyTypeObject
PLy_PlanType
=
{
PyObject_HEAD_INIT
(
NULL
)
0
,
/* ob_size */
"PLyPlan"
,
/* tp_name */
...
...
@@ -1679,13 +1723,13 @@ PyTypeObject PLy_PlanType = {
PLy_plan_doc
,
/* tp_doc */
};
PyMethodDef
PLy_plan_methods
[]
=
{
static
PyMethodDef
PLy_plan_methods
[]
=
{
{
"status"
,
(
PyCFunction
)
PLy_plan_status
,
METH_VARARGS
,
NULL
},
{
NULL
,
NULL
,
0
,
NULL
}
};
PySequenceMethods
PLy_result_as_sequence
=
{
static
PySequenceMethods
PLy_result_as_sequence
=
{
(
inquiry
)
PLy_result_length
,
/* sq_length */
(
binaryfunc
)
0
,
/* sq_concat */
(
intargfunc
)
0
,
/* sq_repeat */
...
...
@@ -1695,7 +1739,7 @@ PySequenceMethods PLy_result_as_sequence = {
(
intintobjargproc
)
PLy_result_ass_slice
,
/* sq_ass_slice */
};
PyTypeObject
PLy_ResultType
=
{
static
PyTypeObject
PLy_ResultType
=
{
PyObject_HEAD_INIT
(
NULL
)
0
,
/* ob_size */
"PLyResult"
,
/* tp_name */
...
...
@@ -1723,14 +1767,15 @@ PyTypeObject PLy_ResultType = {
0
,
/* tp_xxx4 */
PLy_result_doc
,
/* tp_doc */
};
PyMethodDef
PLy_result_methods
[]
=
{
#ifdef NOT_USED
/* Appear to be unused */
static
PyMethodDef
PLy_result_methods
[]
=
{
{
"fetch"
,
(
PyCFunction
)
PLy_result_fetch
,
METH_VARARGS
,
NULL
,},
{
"nrows"
,
(
PyCFunction
)
PLy_result_nrows
,
METH_VARARGS
,
NULL
},
{
"status"
,
(
PyCFunction
)
PLy_result_status
,
METH_VARARGS
,
NULL
},
{
NULL
,
NULL
,
0
,
NULL
}
};
#endif
static
PyMethodDef
PLy_methods
[]
=
{
/*
...
...
@@ -1833,7 +1878,7 @@ PLy_plan_status(PyObject * self, PyObject * args)
/* result object methods
*/
static
PyObject
*
PyObject
*
PLy_result_new
(
void
)
{
PLyResultObject
*
ob
;
...
...
@@ -1853,7 +1898,7 @@ PLy_result_new(void)
return
(
PyObject
*
)
ob
;
}
static
void
void
PLy_result_dealloc
(
PyObject
*
arg
)
{
PLyResultObject
*
ob
=
(
PLyResultObject
*
)
arg
;
...
...
@@ -1867,19 +1912,20 @@ PLy_result_dealloc(PyObject * arg)
PyMem_DEL
(
ob
);
}
static
PyObject
*
PyObject
*
PLy_result_getattr
(
PyObject
*
self
,
char
*
attr
)
{
return
NULL
;
}
static
PyObject
*
#ifdef NOT_USED
/* Appear to be unused */
PyObject
*
PLy_result_fetch
(
PyObject
*
self
,
PyObject
*
args
)
{
return
NULL
;
}
static
PyObject
*
PyObject
*
PLy_result_nrows
(
PyObject
*
self
,
PyObject
*
args
)
{
PLyResultObject
*
ob
=
(
PLyResultObject
*
)
self
;
...
...
@@ -1888,7 +1934,7 @@ PLy_result_nrows(PyObject * self, PyObject * args)
return
ob
->
nrows
;
}
static
PyObject
*
PyObject
*
PLy_result_status
(
PyObject
*
self
,
PyObject
*
args
)
{
PLyResultObject
*
ob
=
(
PLyResultObject
*
)
self
;
...
...
@@ -1896,7 +1942,7 @@ PLy_result_status(PyObject * self, PyObject * args)
Py_INCREF
(
ob
->
status
);
return
ob
->
status
;
}
#endif
int
PLy_result_length
(
PyObject
*
arg
)
{
...
...
@@ -1991,7 +2037,8 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
if
(
!
PyErr_Occurred
())
PyErr_SetString
(
PLy_exc_spi_error
,
"Unknown error in PLy_spi_prepare."
);
return
NULL
;
PLy_elog
(
NOTICE
,
"in function %s:"
,
PLy_procedure_name
(
PLy_last_procedure
));
RERAISE_EXC
();
}
if
(
list
!=
NULL
)
...
...
@@ -2097,7 +2144,7 @@ PLy_spi_execute(PyObject * self, PyObject * args)
enter
();
#if
0
#if
def NOT_USED
/*
* there should - hahaha - be an python exception set so just return
...
...
@@ -2187,7 +2234,8 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, int limit)
if
(
!
PyErr_Occurred
())
PyErr_SetString
(
PLy_exc_error
,
"Unknown error in PLy_spi_execute_plan"
);
return
NULL
;
PLy_elog
(
NOTICE
,
"in function %s:"
,
PLy_procedure_name
(
PLy_last_procedure
));
RERAISE_EXC
();
}
if
(
nargs
)
...
...
@@ -2249,16 +2297,15 @@ PLy_spi_execute_query(char *query, int limit)
if
(
TRAP_EXC
())
{
RESTORE_EXC
();
if
((
!
PLy_restart_in_progress
)
&&
(
!
PyErr_Occurred
()))
PyErr_SetString
(
PLy_exc_spi_error
,
"Unknown error in PLy_spi_execute_query."
);
return
NULL
;
PLy_elog
(
NOTICE
,
"in function %s:"
,
PLy_procedure_name
(
PLy_last_procedure
));
RERAISE_EXC
();
}
rv
=
SPI_exec
(
query
,
limit
);
RESTORE_EXC
();
if
(
rv
<
0
)
{
PLy_exception_set
(
PLy_exc_spi_error
,
...
...
@@ -2311,7 +2358,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
"Unknown error in PLy_spi_execute_fetch_result"
);
Py_DECREF
(
result
);
PLy_typeinfo_dealloc
(
&
args
);
return
NULL
;
RERAISE_EXC
()
;
}
if
(
rows
)
...
...
@@ -2450,13 +2497,33 @@ PLy_init_plpy(void)
elog
(
ERROR
,
"Unable to init plpy."
);
}
/*
* New RExec methods
*/
PyObject
*
PLy_r_open
(
PyObject
*
self
,
PyObject
*
args
)
{
PyErr_SetString
(
PyExc_IOError
,
"can't open files in restricted mode"
);
return
NULL
;
}
static
PyMethodDef
PLy_r_exec_methods
[]
=
{
{
"r_open"
,
(
PyCFunction
)
PLy_r_open
,
METH_VARARGS
,
NULL
},
{
NULL
,
NULL
,
0
,
NULL
}
};
/*
* Init new RExec
*/
void
PLy_init_safe_interp
(
void
)
{
PyObject
*
rmod
;
PyObject
*
rmod
,
*
rexec
,
*
rexec_dict
;
char
*
rname
=
"rexec"
;
int
i
,
imax
;
int
len
;
enter
();
...
...
@@ -2467,19 +2534,93 @@ PLy_init_safe_interp(void)
PyDict_SetItemString
(
PLy_interp_globals
,
rname
,
rmod
);
PLy_interp_safe
=
rmod
;
imax
=
sizeof
(
PLy_importable_modules_list
)
/
sizeof
(
char
*
);
PLy_importable_modules
=
PyTuple_New
(
imax
);
for
(
i
=
0
;
i
<
imax
;
i
++
)
{
PyObject
*
m
=
PyString_FromString
(
PLy_importable_modules_list
[
i
]);
len
=
sizeof
(
PLy_importable_modules_list
)
/
sizeof
(
char
*
);
PLy_importable_modules
=
build_tuple
(
PLy_importable_modules_list
,
len
);
PyTuple_SetItem
(
PLy_importable_modules
,
i
,
m
);
}
len
=
sizeof
(
PLy_ok_posix_names_list
)
/
sizeof
(
char
*
);
PLy_ok_posix_names
=
build_tuple
(
PLy_ok_posix_names_list
,
len
);
len
=
sizeof
(
PLy_ok_sys_names_list
)
/
sizeof
(
char
*
);
PLy_ok_sys_names
=
build_tuple
(
PLy_ok_sys_names_list
,
len
);
PLy_interp_safe_globals
=
PyDict_New
();
if
(
PLy_interp_safe_globals
==
NULL
)
PLy_elog
(
ERROR
,
"Unable to create shared global dictionary."
);
/*
* get an rexec.RExec class
*/
rexec
=
PyDict_GetItemString
(
PyModule_GetDict
(
rmod
),
"RExec"
);
if
(
rexec
==
NULL
||
!
PyClass_Check
(
rexec
))
PLy_elog
(
ERROR
,
"Unable to get RExec object."
);
rexec_dict
=
((
PyClassObject
*
)
rexec
)
->
cl_dict
;
/*
* tweak the list of permitted modules, posix and sys functions
*/
PyDict_SetItemString
(
rexec_dict
,
"ok_builtin_modules"
,
PLy_importable_modules
);
PyDict_SetItemString
(
rexec_dict
,
"ok_posix_names"
,
PLy_ok_posix_names
);
PyDict_SetItemString
(
rexec_dict
,
"ok_sys_names"
,
PLy_ok_sys_names
);
/*
* change the r_open behavior
*/
if
(
populate_methods
(
rexec
,
PLy_r_exec_methods
)
)
PLy_elog
(
ERROR
,
"Failed to update RExec methods."
);
}
/* Helper function to build tuples from string lists */
static
PyObject
*
build_tuple
(
char
*
string_list
[],
int
len
)
{
PyObject
*
tup
=
PyTuple_New
(
len
);
int
i
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
PyObject
*
m
=
PyString_FromString
(
string_list
[
i
]);
PyTuple_SetItem
(
tup
,
i
,
m
);
}
return
tup
;
}
/* Helper function for populating a class with method wrappers. */
static
int
populate_methods
(
PyObject
*
klass
,
PyMethodDef
*
methods
)
{
if
(
!
klass
||
!
methods
)
return
0
;
for
(
;
methods
->
ml_name
;
++
methods
)
{
/* get a wrapper for the built-in function */
PyObject
*
func
=
PyCFunction_New
(
methods
,
NULL
);
PyObject
*
meth
;
int
status
;
if
(
!
func
)
return
-
1
;
/* turn the function into an unbound method */
if
(
!
(
meth
=
PyMethod_New
(
func
,
NULL
,
klass
)))
{
Py_DECREF
(
func
);
return
-
1
;
}
/* add method to dictionary */
status
=
PyDict_SetItemString
(
((
PyClassObject
*
)
klass
)
->
cl_dict
,
methods
->
ml_name
,
meth
);
Py_DECREF
(
meth
);
Py_DECREF
(
func
);
/* stop now if an error occurred, otherwise do the next method */
if
(
status
)
return
status
;
}
return
0
;
}
...
...
@@ -2566,7 +2707,7 @@ PLy_log(volatile int level, PyObject * self, PyObject * args)
* hideously.
*/
elog
(
FATAL
,
"plpython: Aiieee, elog threw an unknown exception!"
);
return
NULL
;
RERAISE_EXC
()
;
}
elog
(
level
,
sv
);
...
...
@@ -2584,6 +2725,18 @@ PLy_log(volatile int level, PyObject * self, PyObject * args)
}
/* Get the last procedure name called by the backend ( the innermost,
* If a plpython procedure call calls the backend and the backend calls
* another plpython procedure )
*/
char
*
PLy_procedure_name
(
PLyProcedure
*
proc
)
{
if
(
proc
==
NULL
)
return
"<unknown procedure>"
;
return
proc
->
proname
;
}
/* output a python traceback/exception via the postgresql elog
* function. not pretty.
*/
...
...
src/pl/plpython/plpython_error.sql
View file @
1ca717f3
...
...
@@ -7,3 +7,11 @@ SELECT invalid_type_uncaught('rick');
SELECT
invalid_type_caught
(
'rick'
);
SELECT
invalid_type_reraised
(
'rick'
);
SELECT
valid_type
(
'rick'
);
-- Security sandbox tests
SELECT
read_file
(
'/etc/passwd'
);
SELECT
write_file
(
'/tmp/plpython'
,
'This is very bad'
);
SELECT
getpid
();
SELECT
uname
();
SELECT
sys_exit
();
SELECT
sys_argv
();
src/pl/plpython/plpython_function.sql
View file @
1ca717f3
...
...
@@ -257,6 +257,12 @@ if len(rv):
return None
'
LANGUAGE
'plpython'
;
/* Flat out syntax error
*/
CREATE
FUNCTION
sql_syntax_error
()
RETURNS
text
AS
'plpy.execute("syntax error")'
LANGUAGE
'plpython'
;
/* check the handling of uncaught python exceptions
*/
...
...
@@ -287,5 +293,36 @@ return seq
'
LANGUAGE
'plpython'
;
CREATE
OR
REPLACE
FUNCTION
read_file
(
text
)
RETURNS
text
AS
'
return open(args[0]).read()
'
LANGUAGE
'plpython'
;
CREATE
OR
REPLACE
FUNCTION
write_file
(
text
,
text
)
RETURNS
text
AS
'
open(args[0],"w").write(args[1])
'
LANGUAGE
'plpython'
;
CREATE
OR
REPLACE
FUNCTION
getpid
()
RETURNS
int4
AS
'
import os
return os.getpid()
'
LANGUAGE
'plpython'
;
CREATE
OR
REPLACE
FUNCTION
uname
()
RETURNS
int4
AS
'
import os
return os.uname()
'
LANGUAGE
'plpython'
;
CREATE
OR
REPLACE
FUNCTION
sys_exit
()
RETURNS
text
AS
'
import sys
return sys.exit()
'
LANGUAGE
'plpython'
;
CREATE
OR
REPLACE
FUNCTION
sys_argv
()
RETURNS
text
AS
'
import sys
return str(sys.argv)
'
LANGUAGE
'plpython'
;
CREATE
OR
REPLACE
FUNCTION
sys_version
()
RETURNS
text
AS
'
import sys
return str(sys.version)
'
LANGUAGE
'plpython'
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment