From: Rafael Kitover Date: Sat, 25 Jul 2009 20:52:17 +0000 (+0000) Subject: add money type support X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=e06ad5d5eca3cad12045953e06fd6b6c72c1027d;p=dbsrgits%2FDBIx-Class-Historic.git add money type support --- diff --git a/lib/DBIx/Class/Storage/DBI/NoBindVars.pm b/lib/DBIx/Class/Storage/DBI/NoBindVars.pm index c3ba153..126b9de 100644 --- a/lib/DBIx/Class/Storage/DBI/NoBindVars.pm +++ b/lib/DBIx/Class/Storage/DBI/NoBindVars.pm @@ -59,8 +59,11 @@ sub _prep_for_execute { foreach my $data (@$bound) { $data = ''.$data if ref $data; + $data = $self->transform_unbound_value($datatype, $data) + if $datatype; + $data = $self->_dbh->quote($data) - if $self->should_quote_value($datatype, $data); + if (!$datatype || $self->should_quote_value($datatype, $data)); $new_sql .= shift(@sql_part) . $data; } @@ -71,7 +74,7 @@ sub _prep_for_execute { } =head2 should_quote_value - + This method is called by L for every column in order to determine if its value should be quoted or not. The arguments are the current column data type and the actual bind value. The return @@ -79,16 +82,25 @@ value is interpreted as: true - do quote, false - do not quote. You should override this in you Storage::DBI:: subclass, if your RDBMS does not like quotes around certain datatypes (e.g. Sybase and integer columns). The default method always returns true (do quote). - + WARNING!!! - + Always validate that the bind-value is valid for the current datatype. Otherwise you may very well open the door to SQL injection attacks. - + =cut - + sub should_quote_value { 1 } +=head2 transform_unbound_value + +Given a datatype and the value to be inserted directly into a SQL query, returns +the necessary SQL fragment to represent that value. + +=cut + +sub transform_unbound_value { $_[2] } + =head1 AUTHORS Brandon Black diff --git a/lib/DBIx/Class/Storage/DBI/Sybase.pm b/lib/DBIx/Class/Storage/DBI/Sybase.pm index b320242..659aad6 100644 --- a/lib/DBIx/Class/Storage/DBI/Sybase.pm +++ b/lib/DBIx/Class/Storage/DBI/Sybase.pm @@ -245,9 +245,9 @@ sub insert { my $blob_cols = $self->_remove_blob_cols($source, $to_insert); -# Sybase has nested transactions fortunately, because we have to do the insert -# in a transaction to avoid race conditions with the SELECT MAX(COL) identity -# method used when placeholders are enabled. +# Sybase has savepoints fortunately, because we have to do the insert in a +# transaction to avoid race conditions with the SELECT MAX(COL) identity method +# used when placeholders are enabled. my $updated_cols = do { local $self->{auto_savepoint} = 1; my $args = \@_; diff --git a/lib/DBIx/Class/Storage/DBI/Sybase/NoBindVars.pm b/lib/DBIx/Class/Storage/DBI/Sybase/NoBindVars.pm index 5053bae..0ca20a4 100644 --- a/lib/DBIx/Class/Storage/DBI/Sybase/NoBindVars.pm +++ b/lib/DBIx/Class/Storage/DBI/Sybase/NoBindVars.pm @@ -51,6 +51,17 @@ sub should_quote_value { return $self->next::method(@_); } +sub transform_unbound_value { + my ($self, $type, $value) = @_; + + if ($type =~ /money/i && defined $value) { + $value =~ s/^\$//; + $value = '$' . $value; + } + + return $value; +} + 1; =head1 NAME diff --git a/t/746mssql.t b/t/746mssql.t index fa8f137..0dbd479 100644 --- a/t/746mssql.t +++ b/t/746mssql.t @@ -33,7 +33,6 @@ $schema->storage->dbh_do (sub { my ($storage, $dbh) = @_; eval { $dbh->do("DROP TABLE artist") }; $dbh->do(<<'SQL'); - CREATE TABLE artist ( artistid INT IDENTITY NOT NULL, name VARCHAR(100), @@ -41,7 +40,6 @@ CREATE TABLE artist ( charfield CHAR(10) NULL, primary key(artistid) ) - SQL }); @@ -80,14 +78,11 @@ $schema->storage->dbh_do (sub { my ($storage, $dbh) = @_; eval { $dbh->do("DROP TABLE money_test") }; $dbh->do(<<'SQL'); - CREATE TABLE money_test ( id INT IDENTITY PRIMARY KEY, amount MONEY NULL ) - SQL - }); my $rs = $schema->resultset('Money'); @@ -116,8 +111,6 @@ $schema->storage->dbh_do (sub { eval { $dbh->do("DROP TABLE Owners") }; eval { $dbh->do("DROP TABLE Books") }; $dbh->do(<<'SQL'); - - CREATE TABLE Books ( id INT IDENTITY (1, 1) NOT NULL, source VARCHAR(100), @@ -130,7 +123,6 @@ CREATE TABLE Owners ( id INT IDENTITY (1, 1) NOT NULL, name VARCHAR(100), ) - SQL }); @@ -268,11 +260,9 @@ $schema->storage->_sql_maker->{name_sep} = '.'; # clean up our mess END { - if (my $dbh = eval { $schema->storage->_dbh }) { - $dbh->do('DROP TABLE artist'); - $dbh->do('DROP TABLE money_test'); - $dbh->do('DROP TABLE Books'); - $dbh->do('DROP TABLE Owners'); - } + if (my $dbh = eval { $schema->storage->_dbh }) { + eval { $dbh->do("DROP TABLE $_") } + for qw/artist money_test Books Owners/; + } } # vim:sw=2 sts=2 diff --git a/t/746sybase.t b/t/746sybase.t index 6d77b4e..e94da41 100644 --- a/t/746sybase.t +++ b/t/746sybase.t @@ -9,7 +9,7 @@ use DBICTest; my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_SYBASE_${_}" } qw/DSN USER PASS/}; -my $TESTS = 29 + 2; +my $TESTS = 35 + 2; if (not ($dsn && $user)) { plan skip_all => @@ -76,7 +76,7 @@ SQL # so we start unconnected $schema->storage->disconnect; -# inserts happen in a txn, so we test txn nesting +# inserts happen in a txn, so we make sure they can nest $schema->txn_begin; # test primary key handling @@ -222,12 +222,51 @@ SQL diag $@ if $@; ok($got eq $new_str, "verified updated blob"); } + +# test MONEY column support + $schema->storage->dbh_do (sub { + my ($storage, $dbh) = @_; + eval { $dbh->do("DROP TABLE money_test") }; + $dbh->do(<<'SQL'); +CREATE TABLE money_test ( + id INT IDENTITY PRIMARY KEY, + amount MONEY NULL +) +SQL + }); + + my $rs = $schema->resultset('Money'); + + my $row; + lives_ok { + $row = $rs->create({ amount => 100 }); + } 'inserted a money value'; + + is eval { $rs->find($row->id)->amount }, 100, 'money value round-trip'; + + lives_ok { + $row->update({ amount => 200 }); + } 'updated a money value'; + + is eval { $rs->find($row->id)->amount }, + 200, 'updated money value round-trip'; + + lives_ok { + $row->update({ amount => undef }); + } 'updated a money value to NULL'; + + my $null_amount = eval { $rs->find($row->id)->amount }; + ok( + (($null_amount == undef) && (not $@)), + 'updated money value to NULL round-trip' + ); + diag $@ if $@; } # clean up our mess END { if (my $dbh = eval { $schema->storage->_dbh }) { - $dbh->do('DROP TABLE artist'); - eval { $dbh->do('DROP TABLE bindtype_test') }; + eval { $dbh->do("DROP TABLE $_") } + for qw/artist bindtype_test money_test/; } }