|
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 | /* |
|