Subject: | bind_param is not sticky |
DBD-Pg-1.32 module in Perl v5.8.1-RC3 on MacOS 10.3
DBI->param_bind($param, undef, $type) doesn't cause the $type to stick, as required by the DBI specification. The following code exhibits this problem:
Schema:
CREATE TABLE test_binary (
id serial NOT NULL,
data_text text,
data_bytea bytea
) WITHOUT OIDS;
Code:
# Create some binary data
my $data = 'Data: ';
$data .= chr($_) for (0..255);
eval {
my $sth = $dbh->prepare( 'INSERT INTO test_binary (data_text, data_bytea) VALUES (?, ?)' );
$sth->bind_param( 2, undef, { pg_type => DBD::Pg::PG_BYTEA } );
$sth->execute($data, $data); # Reports error
$dbh->commit();
};
Attached is a patch that fixes dbd_bind_ph() in dbdimp.c to use the previously bound column type if a new type is not specified. The patch also improves the error message if there actually is a binding conflict.
Obviously, a "workaround" is to specify both data and type during the param_bind call, but that's not always an option. I've run into this problem while using Class::DBI which prebinds types. It prevented me from using BYTEA columns in Class::DBI.
771a772,778
> /* get the place holder */
> phs_svp = hv_fetch(imp_sth->all_params_hv, name, name_len, 0);
> if (phs_svp == NULL) {
> croak("Can't bind unknown placeholder '%s' (%s)",
> name, neatsvpv(ph_namesv,0));
> }
> phs = (phs_t*)(void*)SvPVX(*phs_svp);
798c805,810
<
---
> } else if (phs->is_bound) {
> bind_type = phs->ftype;
> sql_type_info = pg_type_data(bind_type);
> if(!sql_type_info)
> croak("%s is bound to bad type %d",
> name, bind_type);
807,816d818
<
< /* get the place holder */
< phs_svp = hv_fetch(imp_sth->all_params_hv, name, name_len, 0);
< if (phs_svp == NULL) {
< croak("Can't bind unknown placeholder '%s' (%s)",
< name, neatsvpv(ph_namesv,0));
< }
< phs = (phs_t*)(void*)SvPVX(*phs_svp);
<
<
818,819c820,821
< croak("Can't change TYPE of param %s to %d after initial bind",
< phs->name, sql_type);
---
> croak("Can't change TYPE of param %s to %d after initial bind to %d",
> phs->name, bind_type, phs->ftype);