]> granicus.if.org Git - postgresql/commitdiff
Fix plpython to not get totally confused by OUT arguments. (It still doesn't
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 3 May 2008 02:47:48 +0000 (02:47 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 3 May 2008 02:47:48 +0000 (02:47 +0000)
support multiple OUT arguments, though.)

Hannu Krosing

src/pl/plpython/expected/plpython_function.out
src/pl/plpython/expected/plpython_test.out
src/pl/plpython/plpython.c
src/pl/plpython/sql/plpython_function.sql
src/pl/plpython/sql/plpython_test.sql

index e1ffa7302dbd3f5abc7efd66800a8a1d6d2f34b9..4ace0445d9abacc91d4b61b607cc045c696afb26 100644 (file)
@@ -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;
index 170abe7ab6e68250df134238e1a61ea85af5752b..ddd565bbff5fda0d56a630d0a26d3a4e47d317b1 100644 (file)
@@ -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)
+
index 130eca4f71de0e4e1af1244f5c2e4dac256a464a..9fbfe563ee91b4119565abe7a3e7a253a6a422a7 100644 (file)
@@ -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++;
+                       }
                }
 
                /*
index 224d5196a3c236782f695d6bc061c503516da511..cf01e8e0cdc81b2f991614f2dbb50b3c1127a572 100644 (file)
@@ -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;
index dafcae089e92c5b36eb5aaba15e9dd25b45fc422..f7321ab9e006cb7ea31395bd636d175fe3e8d987 100644 (file)
@@ -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');