| [reply] [d/l] [select] |
Sorry about that - PostgreSQL does let you concatenate ('||') text fields. It's been awhile since I had to deal with SQLServer weirdness.
Well then you're either left with running a
transaction around your read/append/write or CAST the text field to varchar then concat (assuming the data can be cast).
I would go for the transaction approach, you'll be sure it'll work with any kind of data.
As for the ugliness it should be easy to make a method to hide the $dbh->{AutoCommit} = 0 (or $dbh->begin_work), read, append, update, $dbh->commit. Don't forget to turn AutoCommit off if it's on. In fact I would just add that in there to be safe.
local $dbh->{AutoCommit} = 0;
local $dbh->{RaiseError} = 1;
# You can RaiseError and eval the transaction
# or you can check $sth->err each time and rollback
eval {
##Do your read and write here
$dbh->commit;
};
if ($@) {
warn "append failed $@";
$dbh->rollback;
}
UPDATE: something similar to this
sub append_to_text {
my $dbh = shift;
my $table = shift;
my $id = shift;
my $col = shift;
my $data = shift;
local $dbh->{RaiseError} = 1;
eval {
$dbh->begin_work();
my $read = qq|
SELECT $col FROM $table
WHERE id = ?
|;
my $update = qq|
UPDATE $table SET $col = ?
WHERE id = ?
|;
my $sth_read = $dbh->prepare($read);
$sth_read->execute($id);
my $row = $sth_read->fetchrow_hashref();
$sth_read->finish();
my $current = $row->{$col};
$current .= $data;
my $rtn = $dbh->do($update,undef,$current,$id);
$dbh->commit() if ($rtn);
};
if ($@) {
warn "Append Failed: $@\nStatement: $DBI::lasth->{Statement}
+";
eval { $dbh->rollback };
}
}
grep
|
One dead unjugged rabbit fish later |
| [reply] [d/l] [select] |
Thanks again grep,
Are you sure that's right? I thought transactions ensured that multiple changes to the database were either all executed or all aborted, but didn't provide any guarantees that about data that was read. Some quick tests seem to confirm this. For example, if I run multiple copies of this program at the same time, the last one to finish clobbers the values written by any previous runs:
#!/usr/bin/perl
use warnings;
use strict;
use constant DSN => 'DBI:mysql:database=test';
use constant DBUSER => 'user';
use constant DBPASS => 'pass';
use DBI;
our $dbh = DBI->connect(DSN, DBUSER, DBPASS, {
AutoCommit => 0,
RaiseError => 1,
} )
or die "Couldn't connect to database: ",$DBI::errstr;
# Create the message and get the ID
my $sth = $dbh->prepare("SELECT a FROM transtest");
$sth->execute();
my $row = $sth->fetchrow_hashref;
warn "$$ a=$row->{a}\n";
sleep(5);
$dbh->do("UPDATE transtest SET a = ?",undef,$row->{a}+1);
warn "$$ done\n";
| [reply] [d/l] |