Commit 61e3c2a5 authored by sikeda's avatar sikeda
Browse files

[dev] Enhancements on SDM.

- SDM::probe_db(): check only tables defined in database description.  Tables defined by user will be intact.
- Cosmetic concern: Now SDM::do_query() and SDM::do_prepared_query() normalize whitespaces in the query strings.  Multiline query can be used more safely.
- New SDM::AS_BLOB() to bind BLOB parameters by SDM::do_prepared_query().  Tested by PostgreSQL 9.1 and SQLite 3, not yet by Oracle.


git-svn-id: https://subversion.renater.fr/sympa/branches/sympa-6.2-branch@10228 05aa8bb8-cd2b-0410-b1d7-8918dfa770ce
parent 9f796e03
......@@ -145,4 +145,22 @@ sub check_key {
return $result;
}
return 1;
# Helper functions to return the binding type and value used by
# do_prepared_query().
# Overridden by inherited classes.
#
# IN: - parameter value
#
# OUT: - One of:
# * An array ( { sql_type => SQL_type }, value ).
# * Single value (i.e. an array with single item), if special
# treatment won't be needed.
# * Empty array () if arguments were not given.
# For BLOB types.
sub AS_BLOB {
return $_[1] if scalar @_ > 1;
return ();
}
1;
......@@ -197,7 +197,7 @@ sub probe_db {
}
}
## Get fields
foreach my $t (@tables) {
foreach my $t (keys %{$db_struct{'mysql'}}) {
$real_struct{$t} = $db_source->get_fields({'table'=>$t});
}
## Check tables structure if we could get it
......@@ -293,7 +293,7 @@ sub check_fields {
}
## Change DB types if different and if update_db_types enabled
if (&Conf::get_robot_conf('*','update_db_field_types') eq 'auto' && &Conf::get_robot_conf('*','db_type') ne 'SQLite') {
if (&Conf::get_robot_conf('*','update_db_field_types') eq 'auto') {
unless (&check_db_field_type(effective_format => $real_struct{$t}{$f},
required_format => $db_struct{&Conf::get_robot_conf('*','db_type')}{$t}{$f})) {
push @{$report_ref}, sprintf("Field '%s' (table '%s' ; database '%s') does NOT have awaited type (%s). Attempting to change it...",$f, $t, &Conf::get_robot_conf('*','db_name'), $db_struct{&Conf::get_robot_conf('*','db_type')}{$t}{$f});
......@@ -580,4 +580,12 @@ sub get_canonical_read_date {
}
}
return 1;
## bound parameters for do_prepared_query().
## returns an array ( { sql_type => SQL_type }, value ),
## single scalar or empty array.
##
sub AS_BLOB {
return $db_source->AS_BLOB(@_);
}
1;
......@@ -342,9 +342,14 @@ sub do_query {
my $query = shift;
my @params = @_;
$query =~ s/^\s+//;
$query =~ s/\s+$//;
my $statement = sprintf $query, @params;
&Log::do_log('debug', "Will perform query '%s'",$statement);
my $s = $statement;
$s =~ s/\n\s*/ /g;
&Log::do_log('debug3', "Will perform query '%s'", $s);
unless ($self->{'sth'} = $self->{'dbh'}->prepare($statement)) {
# Check connection to database in case it would be the cause of the problem.
unless($self->connect()) {
......@@ -391,11 +396,37 @@ sub do_query {
sub do_prepared_query {
my $self = shift;
my $query = shift;
my @params = @_;
my @params = ();
my %types = ();
## get binding types and parameters
my $i = 0;
while (scalar @_) {
my $p = shift;
if (ref $p eq 'HASH') {
# a hashref { sql_type => SQL_type } etc.
$types{$i} = $p;
push @params, shift;
} elsif (ref $p) {
&Log::do_log('err', 'unexpected %s object. Ask developer',
ref $p);
return undef;
} else {
push @params, $p;
}
$i++;
}
my $sth;
unless ($self->{'cached_prepared_statements'}{$query}) {
$query =~ s/^\s+//;
$query =~ s/\s+$//;
$query =~ s/\n\s*/ /g;
&Log::do_log('debug3', "Will perform query '%s'", $query);
if ($self->{'cached_prepared_statements'}{$query}) {
$sth = $self->{'cached_prepared_statements'}{$query};
} else {
&Log::do_log('debug3','Did not find prepared statement for %s. Doing it.',$query);
unless ($sth = $self->{'dbh'}->prepare($query)) {
unless($self->connect()) {
......@@ -408,11 +439,16 @@ sub do_prepared_query {
}
}
}
## bind parameters with special types
## this may be done only once when handle is prepared.
foreach my $i (sort keys %types) {
$sth->bind_param($i + 1, $params[$i], $types{$i});
}
$self->{'cached_prepared_statements'}{$query} = $sth;
}else {
&Log::do_log('debug3','Reusing prepared statement for %s',$query);
}
unless ($self->{'cached_prepared_statements'}{$query}->execute(@params)) {
unless ($sth->execute(@params)) {
# Check database connection in case it would be the cause of the problem.
unless($self->connect()) {
&Log::do_log('err', 'Unable to get a handle to %s database',$self->{'db_name'});
......@@ -429,15 +465,22 @@ sub do_prepared_query {
}
}
}
## bind parameters with special types
## this may be done only once when handle is prepared.
foreach my $i (sort keys %types) {
$sth->bind_param($i + 1, $params[$i], $types{$i});
}
$self->{'cached_prepared_statements'}{$query} = $sth;
unless ($self->{'cached_prepared_statements'}{$query}->execute(@params)) {
unless ($sth->execute(@params)) {
&Log::do_log('err','Unable to execute SQL statement "%s" : %s', $query, $self->{'dbh'}->errstr);
return undef;
}
}
}
return $self->{'cached_prepared_statements'}{$query};
return $sth;
}
sub prepare_query_log_values {
......
......@@ -1090,6 +1090,7 @@ sub db_struct {
$trans_o =~ s/^text.*/varchar2(500)/g;
$trans_o =~ s/^longtext.*/long/g;
$trans_o =~ s/^datetime.*/date/g;
$trans_o =~ s/^mediumblob/blob/g;
#Postgresql
$trans_pg =~ s/^int(1)/smallint/g;
$trans_pg =~ s/^int\(?.*\)?/int4/g;
......@@ -1100,6 +1101,7 @@ sub db_struct {
$trans_pg =~ s/^longtext.*/text/g;
$trans_pg =~ s/^datetime.*/timestamptz/g;
$trans_pg =~ s/^enum.*/varchar(15)/g;
$trans_pg =~ s/^mediumblob/bytea/g;
#Sybase
$trans_syb =~ s/^int.*/numeric/g;
$trans_syb =~ s/^text.*/varchar(500)/g;
......@@ -1107,16 +1109,19 @@ sub db_struct {
$trans_syb =~ s/^bigint.*/numeric/g;
$trans_syb =~ s/^longtext.*/text/g;
$trans_syb =~ s/^enum.*/varchar(15)/g;
$trans_syb =~ s/^mediumblob/long binary/g;
#Sqlite
$trans_sq =~ s/^varchar.*/text/g;
$trans_sq =~ s/^int\(1\).*/numeric/g;
$trans_sq =~ s/^.*int\(1\).*/numeric/g;
$trans_sq =~ s/^int.*/integer/g;
$trans_sq =~ s/^tinyint.*/integer/g;
$trans_sq =~ s/^bigint.*/integer/g;
$trans_sq =~ s/^smallint.*/integer/g;
$trans_sq =~ s/^longtext.*/text/g;
$trans_sq =~ s/^datetime.*/numeric/g;
$trans_sq =~ s/^enum.*/text/g;
$trans_sq =~ s/^mediumblob/none/g;
$db_struct{'mysql'}{$table}{$field} = $trans;
$db_struct{'Pg'}{$table}{$field} = $trans_pg;
$db_struct{'Oracle'}{$table}{$field} = $trans_o;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment