diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index d683e42cf546f3beb35045446b21aa28d319cd87..d645c5c85924f5309a2a257b11242e3d1c275caf 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -1,7 +1,7 @@ /********************************************************************** * plperl.c - perl as a procedural language for PostgreSQL * - * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.119 2006/10/04 00:30:13 momjian Exp $ + * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.120 2006/10/15 18:56:39 tgl Exp $ * **********************************************************************/ @@ -114,6 +114,9 @@ static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger); static SV *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc); static void plperl_init_shared_libs(pTHX); static HV *plperl_spi_execute_fetch_result(SPITupleTable *, int, int); +static SV *newSVstring(const char *str); +static SV **hv_store_string(HV *hv, const char *key, SV *val); +static SV **hv_fetch_string(HV *hv, const char *key); /* * This routine is a crock, and so is everyplace that calls it. The problem @@ -471,61 +474,61 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo) ) ); - hv_store(hv, "name", 4, newSVpv(tdata->tg_trigger->tgname, 0), 0); - hv_store(hv, "relid", 5, newSVpv(relid, 0), 0); + hv_store_string(hv, "name", newSVstring(tdata->tg_trigger->tgname)); + hv_store_string(hv, "relid", newSVstring(relid)); if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event)) { event = "INSERT"; if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event)) - hv_store(hv, "new", 3, - plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc), - 0); + hv_store_string(hv, "new", + plperl_hash_from_tuple(tdata->tg_trigtuple, + tupdesc)); } else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event)) { event = "DELETE"; if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event)) - hv_store(hv, "old", 3, - plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc), - 0); + hv_store_string(hv, "old", + plperl_hash_from_tuple(tdata->tg_trigtuple, + tupdesc)); } else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event)) { event = "UPDATE"; if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event)) { - hv_store(hv, "old", 3, - plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc), - 0); - hv_store(hv, "new", 3, - plperl_hash_from_tuple(tdata->tg_newtuple, tupdesc), - 0); + hv_store_string(hv, "old", + plperl_hash_from_tuple(tdata->tg_trigtuple, + tupdesc)); + hv_store_string(hv, "new", + plperl_hash_from_tuple(tdata->tg_newtuple, + tupdesc)); } } else event = "UNKNOWN"; - hv_store(hv, "event", 5, newSVpv(event, 0), 0); - hv_store(hv, "argc", 4, newSViv(tdata->tg_trigger->tgnargs), 0); + hv_store_string(hv, "event", newSVstring(event)); + hv_store_string(hv, "argc", newSViv(tdata->tg_trigger->tgnargs)); if (tdata->tg_trigger->tgnargs > 0) { AV *av = newAV(); for (i = 0; i < tdata->tg_trigger->tgnargs; i++) - av_push(av, newSVpv(tdata->tg_trigger->tgargs[i], 0)); - hv_store(hv, "args", 4, newRV_noinc((SV *) av), 0); + av_push(av, newSVstring(tdata->tg_trigger->tgargs[i])); + hv_store_string(hv, "args", newRV_noinc((SV *) av)); } - hv_store(hv, "relname", 7, - newSVpv(SPI_getrelname(tdata->tg_relation), 0), 0); + hv_store_string(hv, "relname", + newSVstring(SPI_getrelname(tdata->tg_relation))); - hv_store(hv, "table_name", 10, - newSVpv(SPI_getrelname(tdata->tg_relation), 0), 0); + hv_store_string(hv, "table_name", + newSVstring(SPI_getrelname(tdata->tg_relation))); - hv_store(hv, "table_schema", 12, - newSVpv(SPI_getnspname(tdata->tg_relation), 0), 0); + hv_store_string(hv, "table_schema", + newSVstring(SPI_getnspname(tdata->tg_relation))); if (TRIGGER_FIRED_BEFORE(tdata->tg_event)) when = "BEFORE"; @@ -533,7 +536,7 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo) when = "AFTER"; else when = "UNKNOWN"; - hv_store(hv, "when", 4, newSVpv(when, 0), 0); + hv_store_string(hv, "when", newSVstring(when)); if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event)) level = "ROW"; @@ -541,7 +544,7 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo) level = "STATEMENT"; else level = "UNKNOWN"; - hv_store(hv, "level", 5, newSVpv(level, 0), 0); + hv_store_string(hv, "level", newSVstring(level)); return newRV_noinc((SV *) hv); } @@ -567,7 +570,7 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) tupdesc = tdata->tg_relation->rd_att; - svp = hv_fetch(hvTD, "new", 3, FALSE); + svp = hv_fetch_string(hvTD, "new"); if (!svp) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), @@ -741,9 +744,10 @@ plperl_validator(PG_FUNCTION_ARGS) } -/* Uses mksafefunc/mkunsafefunc to create an anonymous sub whose text is - * supplied in s, and returns a reference to the closure. */ - +/* + * Uses mksafefunc/mkunsafefunc to create an anonymous sub whose text is + * supplied in s, and returns a reference to the closure. + */ static SV * plperl_create_sub(char *s, bool trusted) { @@ -761,8 +765,8 @@ plperl_create_sub(char *s, bool trusted) ENTER; SAVETMPS; PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpv("our $_TD; local $_TD=$_[0]; shift;", 0))); - XPUSHs(sv_2mortal(newSVpv(s, 0))); + XPUSHs(sv_2mortal(newSVstring("our $_TD; local $_TD=$_[0]; shift;"))); + XPUSHs(sv_2mortal(newSVstring(s))); PUTBACK; /* @@ -900,11 +904,7 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo) tmp = OutputFunctionCall(&(desc->arg_out_func[i]), fcinfo->arg[i]); - sv = newSVpv(tmp, 0); -#if PERL_BCDVERSION >= 0x5006000L - if (GetDatabaseEncoding() == PG_UTF8) - SvUTF8_on(sv); -#endif + sv = newSVstring(tmp); XPUSHs(sv_2mortal(sv)); pfree(tmp); } @@ -965,7 +965,7 @@ plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo, tg_trigger = ((TriggerData *) fcinfo->context)->tg_trigger; for (i = 0; i < tg_trigger->tgnargs; i++) - XPUSHs(sv_2mortal(newSVpv(tg_trigger->tgargs[i], 0))); + XPUSHs(sv_2mortal(newSVstring(tg_trigger->tgargs[i]))); PUTBACK; /* Do NOT use G_KEEPERR here */ @@ -1256,7 +1256,6 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) HeapTuple procTup; Form_pg_proc procStruct; char internal_proname[64]; - int proname_len; plperl_proc_desc *prodesc = NULL; int i; SV **svp; @@ -1277,12 +1276,10 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) else sprintf(internal_proname, "__PLPerl_proc_%u_trigger", fn_oid); - proname_len = strlen(internal_proname); - /************************************************************ * Lookup the internal proc name in the hashtable ************************************************************/ - svp = hv_fetch(plperl_proc_hash, internal_proname, proname_len, FALSE); + svp = hv_fetch_string(plperl_proc_hash, internal_proname); if (svp) { bool uptodate; @@ -1484,8 +1481,8 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) internal_proname); } - hv_store(plperl_proc_hash, internal_proname, proname_len, - newSVuv(PTR2UV(prodesc)), 0); + hv_store_string(plperl_proc_hash, internal_proname, + newSVuv(PTR2UV(prodesc))); } ReleaseSysCache(procTup); @@ -1512,36 +1509,27 @@ plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc) char *outputstr; Oid typoutput; bool typisvarlena; - int namelen; - SV *sv; if (tupdesc->attrs[i]->attisdropped) continue; attname = NameStr(tupdesc->attrs[i]->attname); - namelen = strlen(attname); attr = heap_getattr(tuple, i + 1, tupdesc, &isnull); if (isnull) { /* Store (attname => undef) and move on. */ - hv_store(hv, attname, namelen, newSV(0), 0); + hv_store_string(hv, attname, newSV(0)); continue; } /* XXX should have a way to cache these lookups */ - getTypeOutputInfo(tupdesc->attrs[i]->atttypid, &typoutput, &typisvarlena); outputstr = OidOutputFunctionCall(typoutput, attr); - sv = newSVpv(outputstr, 0); -#if PERL_BCDVERSION >= 0x5006000L - if (GetDatabaseEncoding() == PG_UTF8) - SvUTF8_on(sv); -#endif - hv_store(hv, attname, namelen, sv, 0); + hv_store_string(hv, attname, newSVstring(outputstr)); pfree(outputstr); } @@ -1627,10 +1615,10 @@ plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed, result = newHV(); - hv_store(result, "status", strlen("status"), - newSVpv((char *) SPI_result_code_string(status), 0), 0); - hv_store(result, "processed", strlen("processed"), - newSViv(processed), 0); + hv_store_string(result, "status", + newSVstring(SPI_result_code_string(status))); + hv_store_string(result, "processed", + newSViv(processed)); if (status > 0 && tuptable) { @@ -1644,8 +1632,8 @@ plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed, row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc); av_push(rows, row); } - hv_store(result, "rows", strlen("rows"), - newRV_noinc((SV *) rows), 0); + hv_store_string(result, "rows", + newRV_noinc((SV *) rows)); } SPI_freetuptable(tuptable); @@ -1811,7 +1799,7 @@ plperl_spi_query(char *query) if (portal == NULL) elog(ERROR, "SPI_cursor_open() failed:%s", SPI_result_code_string(SPI_result)); - cursor = newSVpv(portal->name, 0); + cursor = newSVstring(portal->name); /* Commit the inner transaction, return to outer xact context */ ReleaseCurrentSubTransaction(); @@ -2065,9 +2053,9 @@ plperl_spi_prepare(char *query, int argc, SV **argv) * Insert a hashtable entry for the plan and return * the key to the caller. ************************************************************/ - hv_store(plperl_query_hash, qdesc->qname, strlen(qdesc->qname), newSVuv(PTR2UV(qdesc)), 0); + hv_store_string(plperl_query_hash, qdesc->qname, newSVuv(PTR2UV(qdesc))); - return newSVpv(qdesc->qname, strlen(qdesc->qname)); + return newSVstring(qdesc->qname); } HV * @@ -2098,7 +2086,7 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) /************************************************************ * Fetch the saved plan descriptor, see if it's o.k. ************************************************************/ - sv = hv_fetch(plperl_query_hash, query, strlen(query), 0); + sv = hv_fetch_string(plperl_query_hash, query); if (sv == NULL) elog(ERROR, "spi_exec_prepared: Invalid prepared query passed"); if (*sv == NULL || !SvOK(*sv)) @@ -2118,7 +2106,7 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) limit = 0; if (attr != NULL) { - sv = hv_fetch(attr, "limit", 5, 0); + sv = hv_fetch_string(attr, "limit"); if (*sv && SvIOK(*sv)) limit = SvIV(*sv); } @@ -2239,7 +2227,7 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv) /************************************************************ * Fetch the saved plan descriptor, see if it's o.k. ************************************************************/ - sv = hv_fetch(plperl_query_hash, query, strlen(query), 0); + sv = hv_fetch_string(plperl_query_hash, query); if (sv == NULL) elog(ERROR, "spi_query_prepared: Invalid prepared query passed"); if (*sv == NULL || !SvOK(*sv)) @@ -2301,7 +2289,7 @@ plperl_spi_query_prepared(char *query, int argc, SV **argv) elog(ERROR, "SPI_cursor_open() failed:%s", SPI_result_code_string(SPI_result)); - cursor = newSVpv(portal->name, 0); + cursor = newSVstring(portal->name); /* Commit the inner transaction, return to outer xact context */ ReleaseCurrentSubTransaction(); @@ -2353,7 +2341,7 @@ plperl_spi_freeplan(char *query) void *plan; plperl_query_desc *qdesc; - sv = hv_fetch(plperl_query_hash, query, strlen(query), 0); + sv = hv_fetch_string(plperl_query_hash, query); if (sv == NULL) elog(ERROR, "spi_exec_freeplan: Invalid prepared query passed"); if (*sv == NULL || !SvOK(*sv)) @@ -2376,3 +2364,59 @@ plperl_spi_freeplan(char *query) SPI_freeplan(plan); } + +/* + * Create a new SV from a string assumed to be in the current database's + * encoding. + */ +static SV * +newSVstring(const char *str) +{ + SV *sv; + + sv = newSVpv(str, 0); +#if PERL_BCDVERSION >= 0x5006000L + if (GetDatabaseEncoding() == PG_UTF8) + SvUTF8_on(sv); +#endif + return sv; +} + +/* + * Store an SV into a hash table under a key that is a string assumed to be + * in the current database's encoding. + */ +static SV ** +hv_store_string(HV *hv, const char *key, SV *val) +{ + int32 klen = strlen(key); + + /* + * This seems nowhere documented, but under Perl 5.8.0 and up, + * hv_store() recognizes a negative klen parameter as meaning + * a UTF-8 encoded key. It does not appear that hashes track + * UTF-8-ness of keys at all in Perl 5.6. + */ +#if PERL_BCDVERSION >= 0x5008000L + if (GetDatabaseEncoding() == PG_UTF8) + klen = -klen; +#endif + return hv_store(hv, key, klen, val, 0); +} + +/* + * Fetch an SV from a hash table under a key that is a string assumed to be + * in the current database's encoding. + */ +static SV ** +hv_fetch_string(HV *hv, const char *key) +{ + int32 klen = strlen(key); + + /* See notes in hv_store_string */ +#if PERL_BCDVERSION >= 0x5008000L + if (GetDatabaseEncoding() == PG_UTF8) + klen = -klen; +#endif + return hv_fetch(hv, key, klen, 0); +}