1
1
/**********************************************************************
2
2
* plperl.c - perl as a procedural language for PostgreSQL
3
3
*
4
- * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.115 2006/08/12 04:16:45 momjian Exp $
4
+ * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.116 2006/08/13 02:37:11 momjian Exp $
5
5
*
6
6
**********************************************************************/
7
7
@@ -52,6 +52,7 @@ typedef struct plperl_proc_desc
52
52
FmgrInfo result_in_func ; /* I/O function and arg for result type */
53
53
Oid result_typioparam ;
54
54
int nargs ;
55
+ int num_out_args ; /* number of out arguments */
55
56
FmgrInfo arg_out_func [FUNC_MAX_ARGS ];
56
57
bool arg_is_rowtype [FUNC_MAX_ARGS ];
57
58
SV * reference ;
@@ -115,6 +116,9 @@ static SV *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc);
115
116
static void plperl_init_shared_libs (pTHX );
116
117
static HV * plperl_spi_execute_fetch_result (SPITupleTable * , int , int );
117
118
119
+ static SV * plperl_convert_to_pg_array (SV * src );
120
+ static SV * plperl_transform_result (plperl_proc_desc * prodesc , SV * result );
121
+
118
122
/*
119
123
* This routine is a crock, and so is everyplace that calls it. The problem
120
124
* is that the cached form of plperl functions/queries is allocated permanently
@@ -404,7 +408,12 @@ plperl_build_tuple_result(HV *perlhash, AttInMetadata *attinmeta)
404
408
(errcode (ERRCODE_UNDEFINED_COLUMN ),
405
409
errmsg ("Perl hash contains nonexistent column \"%s\"" ,
406
410
key )));
407
- if (SvOK (val ) && SvTYPE (val ) != SVt_NULL )
411
+
412
+ /* if value is ref on array do to pg string array conversion */
413
+ if (SvTYPE (val ) == SVt_RV &&
414
+ SvTYPE (SvRV (val )) == SVt_PVAV )
415
+ values [attn - 1 ] = SvPV (plperl_convert_to_pg_array (val ), PL_na );
416
+ else if (SvOK (val ) && SvTYPE (val ) != SVt_NULL )
408
417
values [attn - 1 ] = SvPV (val , PL_na );
409
418
}
410
419
hv_iterinit (perlhash );
@@ -681,12 +690,7 @@ plperl_validator(PG_FUNCTION_ARGS)
681
690
HeapTuple tuple ;
682
691
Form_pg_proc proc ;
683
692
char functyptype ;
684
- int numargs ;
685
- Oid * argtypes ;
686
- char * * argnames ;
687
- char * argmodes ;
688
693
bool istrigger = false;
689
- int i ;
690
694
691
695
/* Get the new function's pg_proc entry */
692
696
tuple = SearchSysCache (PROCOID ,
@@ -714,18 +718,6 @@ plperl_validator(PG_FUNCTION_ARGS)
714
718
format_type_be (proc -> prorettype ))));
715
719
}
716
720
717
- /* Disallow pseudotypes in arguments (either IN or OUT) */
718
- numargs = get_func_arg_info (tuple ,
719
- & argtypes , & argnames , & argmodes );
720
- for (i = 0 ; i < numargs ; i ++ )
721
- {
722
- if (get_typtype (argtypes [i ]) == 'p' )
723
- ereport (ERROR ,
724
- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
725
- errmsg ("plperl functions cannot take type %s" ,
726
- format_type_be (argtypes [i ]))));
727
- }
728
-
729
721
ReleaseSysCache (tuple );
730
722
731
723
/* Postpone body checks if !check_function_bodies */
@@ -1128,6 +1120,8 @@ plperl_func_handler(PG_FUNCTION_ARGS)
1128
1120
/* Return a perl string converted to a Datum */
1129
1121
char * val ;
1130
1122
1123
+ perlret = plperl_transform_result (prodesc , perlret );
1124
+
1131
1125
if (prodesc -> fn_retisarray && SvROK (perlret ) &&
1132
1126
SvTYPE (SvRV (perlret )) == SVt_PVAV )
1133
1127
{
@@ -1256,7 +1250,6 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
1256
1250
char internal_proname [64 ];
1257
1251
int proname_len ;
1258
1252
plperl_proc_desc * prodesc = NULL ;
1259
- int i ;
1260
1253
SV * * svp ;
1261
1254
1262
1255
/* We'll need the pg_proc tuple in any case... */
@@ -1319,6 +1312,12 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
1319
1312
Datum prosrcdatum ;
1320
1313
bool isnull ;
1321
1314
char * proc_source ;
1315
+ int i ;
1316
+ int numargs ;
1317
+ Oid * argtypes ;
1318
+ char * * argnames ;
1319
+ char * argmodes ;
1320
+
1322
1321
1323
1322
/************************************************************
1324
1323
* Allocate a new procedure description block
@@ -1337,6 +1336,25 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
1337
1336
prodesc -> fn_readonly =
1338
1337
(procStruct -> provolatile != PROVOLATILE_VOLATILE );
1339
1338
1339
+
1340
+ /* Disallow pseudotypes in arguments (either IN or OUT) */
1341
+ /* Count number of out arguments */
1342
+ numargs = get_func_arg_info (procTup ,
1343
+ & argtypes , & argnames , & argmodes );
1344
+ for (i = 0 ; i < numargs ; i ++ )
1345
+ {
1346
+ if (get_typtype (argtypes [i ]) == 'p' )
1347
+ ereport (ERROR ,
1348
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1349
+ errmsg ("plperl functions cannot take type %s" ,
1350
+ format_type_be (argtypes [i ]))));
1351
+
1352
+ if (argmodes && argmodes [i ] == PROARGMODE_OUT )
1353
+ prodesc -> num_out_args ++ ;
1354
+
1355
+ }
1356
+
1357
+
1340
1358
/************************************************************
1341
1359
* Lookup the pg_language tuple by Oid
1342
1360
************************************************************/
@@ -1676,6 +1694,8 @@ plperl_return_next(SV *sv)
1676
1694
fcinfo = current_call_data -> fcinfo ;
1677
1695
rsi = (ReturnSetInfo * ) fcinfo -> resultinfo ;
1678
1696
1697
+ sv = plperl_transform_result (prodesc , sv );
1698
+
1679
1699
if (!prodesc -> fn_retisset )
1680
1700
ereport (ERROR ,
1681
1701
(errcode (ERRCODE_SYNTAX_ERROR ),
@@ -1753,7 +1773,16 @@ plperl_return_next(SV *sv)
1753
1773
1754
1774
if (SvOK (sv ) && SvTYPE (sv ) != SVt_NULL )
1755
1775
{
1756
- char * val = SvPV (sv , PL_na );
1776
+ char * val ;
1777
+ SV * array_ret ;
1778
+
1779
+ if (SvROK (sv ) && SvTYPE (SvRV (sv )) == SVt_PVAV )
1780
+ {
1781
+ array_ret = plperl_convert_to_pg_array (sv );
1782
+ sv = array_ret ;
1783
+ }
1784
+
1785
+ val = SvPV (sv , PL_na );
1757
1786
1758
1787
ret = InputFunctionCall (& prodesc -> result_in_func , val ,
1759
1788
prodesc -> result_typioparam , -1 );
@@ -2368,3 +2397,46 @@ plperl_spi_freeplan(char *query)
2368
2397
2369
2398
SPI_freeplan ( plan );
2370
2399
}
2400
+
2401
+ /*
2402
+ * If plerl result is hash and fce result is scalar, it's hash form of
2403
+ * out argument. Then, transform it to scalar
2404
+ */
2405
+
2406
+ static SV *
2407
+ plperl_transform_result (plperl_proc_desc * prodesc , SV * result )
2408
+ {
2409
+ bool exactly_one_field = false;
2410
+ HV * hvr ;
2411
+ SV * val ;
2412
+ char * key ;
2413
+ I32 klen ;
2414
+
2415
+
2416
+ if (prodesc -> num_out_args == 1 && SvOK (result )
2417
+ && SvTYPE (result ) == SVt_RV && SvTYPE (SvRV (result )) == SVt_PVHV )
2418
+ {
2419
+ hvr = (HV * ) SvRV (result );
2420
+ hv_iterinit (hvr );
2421
+
2422
+ while ((val = hv_iternextsv (hvr , & key , & klen )))
2423
+ {
2424
+ if (exactly_one_field )
2425
+ ereport (ERROR ,
2426
+ (errcode (ERRCODE_UNDEFINED_COLUMN ),
2427
+ errmsg ("Perl hash contains nonexistent column \"%s\"" ,
2428
+ key )));
2429
+ exactly_one_field = true;
2430
+ result = val ;
2431
+ }
2432
+
2433
+ if (!exactly_one_field )
2434
+ ereport (ERROR ,
2435
+ (errcode (ERRCODE_UNDEFINED_COLUMN ),
2436
+ errmsg ("Perl hash is empty" )));
2437
+
2438
+ hv_iterinit (hvr );
2439
+ }
2440
+
2441
+ return result ;
2442
+ }
0 commit comments