|
1 | 1 | /**********************************************************************
|
2 | 2 | * plpython.c - python as a procedural language for PostgreSQL
|
3 | 3 | *
|
4 |
| - *$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.108 2008/03/28 00:21:56 tgl Exp $ |
| 4 | + *$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.109 2008/05/03 02:47:47 tgl Exp $ |
5 | 5 | *
|
6 | 6 | *********************************************************************
|
7 | 7 | */
|
@@ -1161,9 +1161,6 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
|
1161 | 1161 | boolisnull;
|
1162 | 1162 | inti,
|
1163 | 1163 | rv;
|
1164 |
| -Datumargnames; |
1165 |
| -Datum*elems; |
1166 |
| -intnelems; |
1167 | 1164 |
|
1168 | 1165 | procStruct= (Form_pg_proc)GETSTRUCT(procTup);
|
1169 | 1166 |
|
@@ -1249,58 +1246,83 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
|
1249 | 1246 | }
|
1250 | 1247 |
|
1251 | 1248 | /*
|
1252 |
| - * now get information required for input conversion of the |
1253 |
| - * procedure's arguments. |
| 1249 | + * Now get information required for input conversion of the |
| 1250 | + * procedure's arguments. Note that we ignore output arguments |
| 1251 | + * here --- since we don't support returning record, and that was |
| 1252 | + * already checked above, there's no need to worry about multiple |
| 1253 | + * output arguments. |
1254 | 1254 | */
|
1255 |
| -proc->nargs=procStruct->pronargs; |
1256 |
| -if (proc->nargs) |
| 1255 | +if (procStruct->pronargs) |
1257 | 1256 | {
|
1258 |
| -argnames=SysCacheGetAttr(PROCOID,procTup,Anum_pg_proc_proargnames,&isnull); |
1259 |
| -if (!isnull) |
| 1257 | +Oid*types; |
| 1258 | +char**names, |
| 1259 | +*modes; |
| 1260 | +inti, |
| 1261 | +pos, |
| 1262 | +total; |
| 1263 | + |
| 1264 | +/* extract argument type info from the pg_proc tuple */ |
| 1265 | +total=get_func_arg_info(procTup,&types,&names,&modes); |
| 1266 | + |
| 1267 | +/* count number of in+inout args into proc->nargs */ |
| 1268 | +if (modes==NULL) |
| 1269 | +proc->nargs=total; |
| 1270 | +else |
1260 | 1271 | {
|
1261 |
| -/* XXX this code is WRONG if there are any output arguments */ |
1262 |
| -deconstruct_array(DatumGetArrayTypeP(argnames),TEXTOID,-1, false,'i', |
1263 |
| -&elems,NULL,&nelems); |
1264 |
| -if (nelems!=proc->nargs) |
1265 |
| -elog(ERROR, |
1266 |
| -"proargnames must have the same number of elements " |
1267 |
| -"as the function has arguments"); |
1268 |
| -proc->argnames= (char**)PLy_malloc(sizeof(char*)*proc->nargs); |
1269 |
| -memset(proc->argnames,0,sizeof(char*)*proc->nargs); |
| 1272 | +/* proc->nargs was initialized to 0 above */ |
| 1273 | +for (i=0;i<total;i++) |
| 1274 | +{ |
| 1275 | +if (modes[i]!='o') |
| 1276 | +(proc->nargs)++; |
| 1277 | +} |
1270 | 1278 | }
|
1271 |
| -} |
1272 |
| -for (i=0;i<proc->nargs;i++) |
1273 |
| -{ |
1274 |
| -HeapTupleargTypeTup; |
1275 |
| -Form_pg_typeargTypeStruct; |
1276 | 1279 |
|
1277 |
| -argTypeTup=SearchSysCache(TYPEOID, |
1278 |
| -ObjectIdGetDatum(procStruct->proargtypes.values[i]), |
1279 |
| -0,0,0); |
1280 |
| -if (!HeapTupleIsValid(argTypeTup)) |
1281 |
| -elog(ERROR,"cache lookup failed for type %u", |
1282 |
| -procStruct->proargtypes.values[i]); |
1283 |
| -argTypeStruct= (Form_pg_type)GETSTRUCT(argTypeTup); |
| 1280 | +proc->argnames= (char**)PLy_malloc(sizeof(char*)*proc->nargs); |
| 1281 | +for (i=pos=0;i<total;i++) |
| 1282 | +{ |
| 1283 | +HeapTupleargTypeTup; |
| 1284 | +Form_pg_typeargTypeStruct; |
1284 | 1285 |
|
1285 |
| -/* Disallow pseudotype argument */ |
1286 |
| -if (argTypeStruct->typtype==TYPTYPE_PSEUDO) |
1287 |
| -ereport(ERROR, |
1288 |
| -(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
1289 |
| -errmsg("plpython functions cannot take type %s", |
1290 |
| -format_type_be(procStruct->proargtypes.values[i])))); |
1291 |
| - |
1292 |
| -if (argTypeStruct->typtype!=TYPTYPE_COMPOSITE) |
1293 |
| -PLy_input_datum_func(&(proc->args[i]), |
1294 |
| -procStruct->proargtypes.values[i], |
1295 |
| -argTypeTup); |
1296 |
| -else |
1297 |
| -proc->args[i].is_rowtype=2;/* still need to set I/O funcs */ |
| 1286 | +if (modes&&modes[i]=='o')/* skip OUT arguments */ |
| 1287 | +continue; |
| 1288 | + |
| 1289 | +Assert(types[i]==procStruct->proargtypes.values[pos]); |
| 1290 | + |
| 1291 | +argTypeTup=SearchSysCache(TYPEOID, |
| 1292 | +ObjectIdGetDatum(types[i]), |
| 1293 | +0,0,0); |
| 1294 | +if (!HeapTupleIsValid(argTypeTup)) |
| 1295 | +elog(ERROR,"cache lookup failed for type %u",types[i]); |
| 1296 | +argTypeStruct= (Form_pg_type)GETSTRUCT(argTypeTup); |
| 1297 | + |
| 1298 | +/* check argument type is OK, set up I/O function info */ |
| 1299 | +switch (argTypeStruct->typtype) |
| 1300 | +{ |
| 1301 | +caseTYPTYPE_PSEUDO: |
| 1302 | +/* Disallow pseudotype argument */ |
| 1303 | +ereport(ERROR, |
| 1304 | +(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 1305 | +errmsg("plpython functions cannot take type %s", |
| 1306 | +format_type_be(types[i])))); |
| 1307 | +break; |
| 1308 | +caseTYPTYPE_COMPOSITE: |
| 1309 | +/* we'll set IO funcs at first call */ |
| 1310 | +proc->args[pos].is_rowtype=2; |
| 1311 | +break; |
| 1312 | +default: |
| 1313 | +PLy_input_datum_func(&(proc->args[pos]), |
| 1314 | +types[i], |
| 1315 | +argTypeTup); |
| 1316 | +break; |
| 1317 | +} |
1298 | 1318 |
|
1299 |
| -ReleaseSysCache(argTypeTup); |
| 1319 | +/* get argument name */ |
| 1320 | +proc->argnames[pos]=names ?PLy_strdup(names[i]) :NULL; |
1300 | 1321 |
|
1301 |
| -/* Fetch argument name */ |
1302 |
| -if (proc->argnames) |
1303 |
| -proc->argnames[i]=PLy_strdup(TextDatumGetCString(elems[i])); |
| 1322 | +ReleaseSysCache(argTypeTup); |
| 1323 | + |
| 1324 | +pos++; |
| 1325 | +} |
1304 | 1326 | }
|
1305 | 1327 |
|
1306 | 1328 | /*
|
|