aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-05-03 02:47:48 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-05-03 02:47:48 +0000
commitbdc7dd6799ce6effc48de58ca9ecbec82461d8b6 (patch)
tree940bcb9df06f6f6d81d54368968c7799ab3c59fc /src
parentd61eecb5a17d1b9373ca75fb4d6de4e35ba3f640 (diff)
downloadpostgresql-bdc7dd6799ce6effc48de58ca9ecbec82461d8b6.tar.gz
postgresql-bdc7dd6799ce6effc48de58ca9ecbec82461d8b6.zip
Fix plpython to not get totally confused by OUT arguments. (It still doesn't
support multiple OUT arguments, though.) Hannu Krosing
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpython/expected/plpython_function.out11
-rw-r--r--src/pl/plpython/expected/plpython_test.out15
-rw-r--r--src/pl/plpython/plpython.c118
-rw-r--r--src/pl/plpython/sql/plpython_function.sql13
-rw-r--r--src/pl/plpython/sql/plpython_test.sql5
5 files changed, 114 insertions, 48 deletions
diff --git a/src/pl/plpython/expected/plpython_function.out b/src/pl/plpython/expected/plpython_function.out
index e1ffa7302db..4ace0445d9a 100644
--- a/src/pl/plpython/expected/plpython_function.out
+++ b/src/pl/plpython/expected/plpython_function.out
@@ -436,3 +436,14 @@ elif typ == 'obj':
type_record.second = second
return type_record
$$ LANGUAGE plpythonu;
+CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
+return first + '_in_to_out';
+$$ LANGUAGE plpythonu;
+-- this doesn't work yet :-(
+CREATE FUNCTION test_in_out_params_multi(first in text,
+ second out text, third out text) AS $$
+return first + '_record_in_to_out';
+$$ LANGUAGE plpythonu;
+CREATE FUNCTION test_inout_params(first inout text) AS $$
+return first + '_inout';
+$$ LANGUAGE plpythonu;
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
index 170abe7ab6e..ddd565bbff5 100644
--- a/src/pl/plpython/expected/plpython_test.out
+++ b/src/pl/plpython/expected/plpython_test.out
@@ -539,3 +539,18 @@ SELECT * FROM test_type_record_as('obj', null, null, true);
|
(1 row)
+SELECT * FROM test_in_out_params('test_in');
+ second
+-------------------
+ test_in_in_to_out
+(1 row)
+
+-- this doesn't work yet :-(
+SELECT * FROM test_in_out_params_multi('test_in');
+ERROR: plpython functions cannot return type record
+SELECT * FROM test_inout_params('test_in');
+ first
+---------------
+ test_in_inout
+(1 row)
+
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index 130eca4f71d..9fbfe563ee9 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -1,7 +1,7 @@
/**********************************************************************
* plpython.c - python as a procedural language for PostgreSQL
*
- * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.108 2008/03/28 00:21:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.109 2008/05/03 02:47:47 tgl Exp $
*
*********************************************************************
*/
@@ -1161,9 +1161,6 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
bool isnull;
int i,
rv;
- Datum argnames;
- Datum *elems;
- int nelems;
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
@@ -1249,58 +1246,83 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
}
/*
- * now get information required for input conversion of the
- * procedure's arguments.
+ * Now get information required for input conversion of the
+ * procedure's arguments. Note that we ignore output arguments
+ * here --- since we don't support returning record, and that was
+ * already checked above, there's no need to worry about multiple
+ * output arguments.
*/
- proc->nargs = procStruct->pronargs;
- if (proc->nargs)
+ if (procStruct->pronargs)
{
- argnames = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_proargnames, &isnull);
- if (!isnull)
+ Oid *types;
+ char **names,
+ *modes;
+ int i,
+ pos,
+ total;
+
+ /* extract argument type info from the pg_proc tuple */
+ total = get_func_arg_info(procTup, &types, &names, &modes);
+
+ /* count number of in+inout args into proc->nargs */
+ if (modes == NULL)
+ proc->nargs = total;
+ else
{
- /* XXX this code is WRONG if there are any output arguments */
- deconstruct_array(DatumGetArrayTypeP(argnames), TEXTOID, -1, false, 'i',
- &elems, NULL, &nelems);
- if (nelems != proc->nargs)
- elog(ERROR,
- "proargnames must have the same number of elements "
- "as the function has arguments");
- proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
- memset(proc->argnames, 0, sizeof(char *) * proc->nargs);
+ /* proc->nargs was initialized to 0 above */
+ for (i = 0; i < total; i++)
+ {
+ if (modes[i] != 'o')
+ (proc->nargs)++;
+ }
}
- }
- for (i = 0; i < proc->nargs; i++)
- {
- HeapTuple argTypeTup;
- Form_pg_type argTypeStruct;
- argTypeTup = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(procStruct->proargtypes.values[i]),
- 0, 0, 0);
- if (!HeapTupleIsValid(argTypeTup))
- elog(ERROR, "cache lookup failed for type %u",
- procStruct->proargtypes.values[i]);
- argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
+ proc->argnames = (char **) PLy_malloc(sizeof(char *) * proc->nargs);
+ for (i = pos = 0; i < total; i++)
+ {
+ HeapTuple argTypeTup;
+ Form_pg_type argTypeStruct;
- /* Disallow pseudotype argument */
- if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("plpython functions cannot take type %s",
- format_type_be(procStruct->proargtypes.values[i]))));
-
- if (argTypeStruct->typtype != TYPTYPE_COMPOSITE)
- PLy_input_datum_func(&(proc->args[i]),
- procStruct->proargtypes.values[i],
- argTypeTup);
- else
- proc->args[i].is_rowtype = 2; /* still need to set I/O funcs */
+ if (modes && modes[i] == 'o') /* skip OUT arguments */
+ continue;
+
+ Assert(types[i] == procStruct->proargtypes.values[pos]);
+
+ argTypeTup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(types[i]),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(argTypeTup))
+ elog(ERROR, "cache lookup failed for type %u", types[i]);
+ argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
+
+ /* check argument type is OK, set up I/O function info */
+ switch (argTypeStruct->typtype)
+ {
+ case TYPTYPE_PSEUDO:
+ /* Disallow pseudotype argument */
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("plpython functions cannot take type %s",
+ format_type_be(types[i]))));
+ break;
+ case TYPTYPE_COMPOSITE:
+ /* we'll set IO funcs at first call */
+ proc->args[pos].is_rowtype = 2;
+ break;
+ default:
+ PLy_input_datum_func(&(proc->args[pos]),
+ types[i],
+ argTypeTup);
+ break;
+ }
- ReleaseSysCache(argTypeTup);
+ /* get argument name */
+ proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL;
- /* Fetch argument name */
- if (proc->argnames)
- proc->argnames[i] = PLy_strdup(TextDatumGetCString(elems[i]));
+ ReleaseSysCache(argTypeTup);
+
+ pos++;
+ }
}
/*
diff --git a/src/pl/plpython/sql/plpython_function.sql b/src/pl/plpython/sql/plpython_function.sql
index 224d5196a3c..cf01e8e0cdc 100644
--- a/src/pl/plpython/sql/plpython_function.sql
+++ b/src/pl/plpython/sql/plpython_function.sql
@@ -480,3 +480,16 @@ elif typ == 'obj':
return type_record
$$ LANGUAGE plpythonu;
+CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
+return first + '_in_to_out';
+$$ LANGUAGE plpythonu;
+
+-- this doesn't work yet :-(
+CREATE FUNCTION test_in_out_params_multi(first in text,
+ second out text, third out text) AS $$
+return first + '_record_in_to_out';
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION test_inout_params(first inout text) AS $$
+return first + '_inout';
+$$ LANGUAGE plpythonu;
diff --git a/src/pl/plpython/sql/plpython_test.sql b/src/pl/plpython/sql/plpython_test.sql
index dafcae089e9..f7321ab9e00 100644
--- a/src/pl/plpython/sql/plpython_test.sql
+++ b/src/pl/plpython/sql/plpython_test.sql
@@ -143,3 +143,8 @@ SELECT * FROM test_type_record_as('obj', 'one', null, false);
SELECT * FROM test_type_record_as('obj', null, 2, false);
SELECT * FROM test_type_record_as('obj', 'three', 3, false);
SELECT * FROM test_type_record_as('obj', null, null, true);
+
+SELECT * FROM test_in_out_params('test_in');
+-- this doesn't work yet :-(
+SELECT * FROM test_in_out_params_multi('test_in');
+SELECT * FROM test_inout_params('test_in');