0

I've a Perl script that builds up an sql cmd to set certain fields to NULL in a certain table in an MS Access db ( sorry). Here's a simplified mockup.

my $nonKeyFields_hashref = { "country" => "ZZZ",
                             "address3" => "FOO"
                           };
my $keyFields_hashref = { "address1" => "1212 O'Mally Street",    # embedded single quote here is causing the problem
                          "client ID" => "1234567"
                        };
my $sqlCmd = "UPDATE myTable SET ";
$sqlCmd .= join( ", " , map{ "[?} = NULL "} keys $nonKeyFields_hashref;
$sqlCmd .= " WHERE ";
$sqlCmd .= join( " AND " , map{ "[?} = ? "} keys $keyFields_hashref;

# sqlCmd contains "UPDATE myTable SET [?] = NULL, [?} = NULL WHERE [?] = ? AND [?] = ?"

$sth = $dbh->prepare( $sqlCmd);
if( !defined( $sth)) {
  _pushErrorMsg("sth failed to define - ".$DBI::errstr);
  $errorHit = 1;
} else {
  my @cmd_arry = ();
  push( @cmd_arry, $_ ) for keys $nonKeyFields_hashref;
  push( @cmd_arry, $_ , $keyFields_hashref->{$_} ) for keys $keyFields_hashref;
  print Dumper( @cmd_arry);

  # dumper shows @cmd_arry contains ("country", "address3", "address1", "1212 O'Mally Street", "client ID", "1234567")
  # which is six elements, which jibes with the query's question-marks

  $sth->execute( @cmd_arry);    # errors here with the given message
  ....
}

this code works great when the data does NOT contain nasty embedded single-quotes. I'd hoped the binding would solve this problem but no such luck.

Anyone have a solution to this single-quote issue?

Thanks in advance,

Still-learning Steve.

user4035
  • 22,508
  • 11
  • 59
  • 94
user1201168
  • 415
  • 6
  • 19

2 Answers2

0

That code contains syntax errors due to a) missing closing ) on the join calls b) missing use for Data::Dumper. I'm assuming you are using a recent Perl since you seem to be expecting $hash_references are automatically dereferenced.

It is unusual for a database engine to accept parameters for column names - this definitely would not work with most databases.

The single quote you are talking about has no impact on this script as far as I can see - it is just broken wrt the code in the else pushing too many paramaters for the SQL statement. The SQL statement wants 4 column names and you push 4 column names and 2 values.

I presume you meant " push( @cmd_arry, $_ , $keyFields_hashref->{$_}" to be "push( @cmd_arry, $_".

bohica
  • 5,932
  • 3
  • 23
  • 28
  • I've just realised you are the same person who asked http://stackoverflow.com/questions/17479928/trouble-creating-table-with-a-field-of-type-memo-in-access-db-using-perl-dbi-odb and didn't mark my answer. Didn't it answer your question? – bohica Jul 22 '13 at 16:32
0

Some slight refactoring did the trick:

$sqlCmd = "UPDATE [$tableName] SET ";
$sqlCmd .= join( ", ", map { "[$_] = NULL "} keys $nonKeyFields_hashref);
$sqlCmd .= " WHERE ";
$sqlCmd .= join( " AND ", map { "[$_] = ? "} keys $keyFields_hashref);
# sneaky values may contain embedded single-quotes for GoGo's , 4343 Little's Court, etc

my $sth = undef;
$sth = $dbh->prepare( $sqlCmd);
if( !defined( $sth)) {
  _pushErrorMsg("sth failed to define - ".$DBI::errstr);
  $errorHit = 1;
} else {
  my @cmd_arry = ();
  push( @cmd_arry, $keyFields_hashref->{$_} )  for keys( $keyFields_hashref);
  print Dumper( @cmd_arry);
  my $resultCnt = $sth->execute( @cmd_arry);
  if( my $errorMsg = $dbh->errstr ) 
 ....

Thanks to all who responded!

Still-learning Steve

user1201168
  • 415
  • 6
  • 19