~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to lib/GenTest/Executor/JavaDB.pm

merge from internal tree

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package GenTest::Executor::JavaDB;
 
2
 
 
3
require Exporter;
 
4
 
 
5
@ISA = qw(GenTest::Executor);
 
6
 
 
7
use strict;
 
8
use DBI;
 
9
use GenTest;
 
10
use GenTest::Constants;
 
11
use GenTest::Result;
 
12
use GenTest::Executor;
 
13
use GenTest::Translator;
 
14
use GenTest::Translator::MysqlDML2ANSI;
 
15
use GenTest::Translator::Mysqldump2ANSI;
 
16
use GenTest::Translator::MysqlDML2javadb;
 
17
use GenTest::Translator::Mysqldump2javadb;
 
18
use Time::HiRes;
 
19
 
 
20
my %caches;
 
21
 
 
22
my %reported_errors;
 
23
 
 
24
my %acceptedErrors = (
 
25
    "42Y55" => 1 # DROP TABLE on non-existing table is accepted since
 
26
                 # tests rely on non-standard MySQL DROP IF EXISTS;
 
27
    );
 
28
 
 
29
sub init {
 
30
    
 
31
    my $self = shift;
 
32
 
 
33
    ## The jdbc URL may contain both = and ;. These characters have to
 
34
    ## be encoded in order to pass unharmed through DBI. We assume
 
35
    ## here, that url=.... is the last part of the dsn, and encode
 
36
    ## everything after url=
 
37
 
 
38
    my ($dsn_part1,$dsn_part2) = split(/url=/,$self->dsn());
 
39
 
 
40
    $dsn_part2 =~ s/([=;])/uc sprintf("%%%02x",ord($1))/eg;
 
41
 
 
42
    my $dbh = DBI->connect($dsn_part1."url=".$dsn_part2, undef, undef, 
 
43
                           {
 
44
                               PrintError => 0,
 
45
                               RaiseError => 0,
 
46
                               AutoCommit => 1
 
47
                           });
 
48
    
 
49
    if (not defined $dbh) {
 
50
        say("connect() to dsn ".$self->dsn()." failed: ".$DBI::errstr);
 
51
        return STATUS_ENVIRONMENT_FAILURE;
 
52
    }
 
53
    
 
54
    $self->setDbh($dbh);
 
55
    
 
56
    return STATUS_OK;
 
57
}
 
58
 
 
59
sub execute {
 
60
    my ($self, $query, $silent) = @_;
 
61
 
 
62
    my $dbh = $self->dbh();
 
63
 
 
64
    return GenTest::Result->new( 
 
65
        query => $query, 
 
66
        status => STATUS_UNKNOWN_ERROR ) 
 
67
        if not defined $dbh;
 
68
 
 
69
    $query = $self->preprocess($query);
 
70
 
 
71
    ## This may be generalized into a translator which is a pipe
 
72
 
 
73
    my @pipe = (GenTest::Translator::Mysqldump2javadb->new(),
 
74
                GenTest::Translator::MysqlDML2javadb->new());
 
75
 
 
76
    foreach my $p (@pipe) {
 
77
        $query = $p->translate($query);
 
78
        return GenTest::Result->new( 
 
79
            query => $query, 
 
80
            status => STATUS_WONT_HANDLE ) 
 
81
            if not $query;
 
82
 
 
83
    }
 
84
 
 
85
    if (!$dbh->ping()) {
 
86
        ## Reinit if connection is dead
 
87
        say("JavaDB connection is dead. Reconnect");
 
88
        $self->init();
 
89
        $dbh=$self->dbh();
 
90
    }
 
91
 
 
92
    # Autocommit ?
 
93
 
 
94
    my $db = $self->getName()." ".$self->version();
 
95
 
 
96
    my $start_time = Time::HiRes::time();
 
97
 
 
98
 
 
99
    my $sth = $dbh->prepare($query);
 
100
 
 
101
    if (defined $dbh->err()) {
 
102
        ## Error on prepare. Check for the ones we accept (E.g. DROP
 
103
        ## TABLE on non-existing table)
 
104
        if (not defined $acceptedErrors{$dbh->state()}) {
 
105
            my $errstr = $db.":".$dbh->state().":".$dbh->errstr();
 
106
            say($errstr . "($query)") if !$silent;
 
107
            $self->[EXECUTOR_ERROR_COUNTS]->{$errstr}++ if rqg_debug() && !$silent;
 
108
            return GenTest::Result->new(
 
109
                query       => $query,
 
110
                status      => $self->findStatus($dbh->state()),
 
111
                err         => $dbh->err(),
 
112
                errstr      => $dbh->errstr(),
 
113
                sqlstate    => $dbh->state(),
 
114
                start_time  => $start_time,
 
115
                end_time    => Time::HiRes::time()
 
116
                );
 
117
        } else {
 
118
            ## E.g. DROP on non-existing table
 
119
            return GenTest::Result->new(
 
120
                query       => $query,
 
121
                status      => STATUS_OK,
 
122
                affected_rows => 0,
 
123
                start_time  => $start_time,
 
124
                end_time    => Time::HiRes::time()
 
125
                );
 
126
        }
 
127
    }
 
128
 
 
129
    my $affected_rows = $sth->execute();
 
130
    
 
131
    my $end_time = Time::HiRes::time();
 
132
    
 
133
    my $err = $sth->err();
 
134
    my $result;
 
135
 
 
136
    if (defined $err) {         
 
137
        ## Error on EXECUTE
 
138
        my $errstr = $db.":".$dbh->state().":".$dbh->errstr();
 
139
        say($errstr . "($query)") if !$silent;
 
140
        $self->[EXECUTOR_ERROR_COUNTS]->{$errstr}++ if rqg_debug() && !$silent;
 
141
        return GenTest::Result->new(
 
142
            query       => $query,
 
143
            status      => $self->findStatus($dbh->state()),
 
144
            err         => $dbh->err(),
 
145
            errstr      => $dbh->errstr(),
 
146
            sqlstate    => $dbh->state(),
 
147
            start_time  => $start_time,
 
148
            end_time    => $end_time
 
149
            );
 
150
    } elsif ((not defined $sth->{NUM_OF_FIELDS}) || ($sth->{NUM_OF_FIELDS} == 0)) {
 
151
        ## DDL/UPDATE/INSERT/DROP/DELETE
 
152
        $result = GenTest::Result->new(
 
153
            query       => $query,
 
154
            status      => STATUS_OK,
 
155
            affected_rows   => $affected_rows,
 
156
            start_time  => $start_time,
 
157
            end_time    => $end_time
 
158
            );
 
159
        $self->[EXECUTOR_ERROR_COUNTS]->{'(no error)'}++ if rqg_debug() && !$silent;
 
160
    } else {
 
161
        ## Query
 
162
        
 
163
        # We do not use fetchall_arrayref() due to a memory leak
 
164
        # We also copy the row explicitly into a fresh array
 
165
        # otherwise the entire @data array ends up referencing row #1 only
 
166
        my @data;
 
167
        while (my $row = $sth->fetchrow_arrayref()) {
 
168
            $self->normalize($row);
 
169
            my @row = @$row;
 
170
            push @data, \@row;
 
171
        }   
 
172
        
 
173
        $result = GenTest::Result->new(
 
174
            query       => $query,
 
175
            status      => STATUS_OK,
 
176
            affected_rows   => $affected_rows,
 
177
            data        => \@data,
 
178
            start_time  => $start_time,
 
179
            end_time    => $end_time
 
180
            );
 
181
        
 
182
        $self->[EXECUTOR_ERROR_COUNTS]->{'(no error)'}++ if rqg_debug() && !$silent;
 
183
    }
 
184
 
 
185
    $sth->finish();
 
186
 
 
187
    return $result;
 
188
}
 
189
 
 
190
 
 
191
## Normalizing is in this case the process of making the rsult look
 
192
## like it came from MySQL
 
193
sub normalize {
 
194
    my ($self, $row) = @_;
 
195
 
 
196
    my @row = @$row;
 
197
 
 
198
    foreach my $e (@row) {
 
199
        ## Remove .0 fractions from timestamps
 
200
        $e =~ s/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\.0+$/\1/;
 
201
    }
 
202
}
 
203
 
 
204
 
 
205
sub DESTROY {
 
206
        my ($self) = @_;
 
207
        if (rqg_debug()) {
 
208
                say("Statistics for Executor ".$self->dsn()); 
 
209
                use Data::Dumper;
 
210
                $Data::Dumper::Sortkeys = 1;
 
211
                say("Rows returned:");
 
212
                print Dumper $self->[EXECUTOR_ROW_COUNTS];
 
213
                say("Explain items:");
 
214
                print Dumper $self->[EXECUTOR_EXPLAIN_COUNTS];
 
215
                say("Errors:");
 
216
                print Dumper $self->[EXECUTOR_ERROR_COUNTS];
 
217
                say("Rare EXPLAIN items:");
 
218
                print Dumper $self->[EXECUTOR_EXPLAIN_QUERIES];
 
219
        }
 
220
        $self->dbh()->disconnect();
 
221
}
 
222
 
 
223
sub version {
 
224
        my ($self) = @_;
 
225
        return "Version N/A"; # Not implemented in DBD::JDBC
 
226
}
 
227
 
 
228
 
 
229
1;