1
# Copyright (C) 2008-2009 Sun Microsystems, Inc. All rights reserved.
2
# Use is subject to license terms.
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; version 2 of the License.
8
# This program is distributed in the hope that it will be useful, but
9
# WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
# General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18
# 2-way and 3-way result set comparartor with minority report in the
19
# case of 3-way comparision. Does also the same job as
20
# ResultsetComparator and may replace it for 2-ay comparision.
22
package GenTest::Validator::ResultsetComparator3Simplify;
25
@ISA = qw(GenTest GenTest::Validator);
30
use GenTest::Constants;
31
use GenTest::Comparator;
33
use GenTest::Validator;
34
use GenTest::Simplifier::SQL;
35
use GenTest::Simplifier::Test;
39
my ($self, $q, $s1, $s2, $res1, $res2) = @_;
41
my $outcome = GenTest::Comparator::compare($res1, $res2);
43
if ($outcome == STATUS_LENGTH_MISMATCH) {
44
if ($q =~ m{^\s*select}io) {
46
say("Result length mismatch between $s1 and $s2 (".$res1->rows()." vs. ".$res2->rows().")");
47
say("Query1: " . $res1->query());
48
say("Query2: " . $res2->query());
49
say(GenTest::Comparator::dumpDiff($res1,$res2));
52
say("Affected_rows mismatch between $s1 and $s2 (".$res1->affectedRows()." vs. ".$res2->affectedRows().")");
53
say("Query1: " . $res1->query());
54
say("Query2: " . $res2->query());
56
} elsif ($outcome == STATUS_CONTENT_MISMATCH) {
58
say("Result content mismatch between $s1 and $s2.");
59
say("Query1: " . $res1->query());
60
say("Query2: " . $res2->query());
61
say(GenTest::Comparator::dumpDiff($res1, $res2));
69
my ($self, $query, $ex1, $ex2, $r1, $r2) = @_;
71
my @executors = ( $ex1, $ex2 );
73
my @results = ($r1, $r2);
75
my $simplifier_sql = GenTest::Simplifier::SQL->new(
77
my $oracle_query = shift;
80
foreach my $executor (@executors) {
81
push @oracle_results, $executor->execute($oracle_query, 1);
83
my $oracle_compare = GenTest::Comparator::compare($oracle_results[0], $oracle_results[1]);
85
($oracle_compare == STATUS_LENGTH_MISMATCH) ||
86
($oracle_compare == STATUS_CONTENT_MISMATCH)
88
return ORACLE_ISSUE_STILL_REPEATABLE;
90
return ORACLE_ISSUE_NO_LONGER_REPEATABLE;
95
my $simplified_query = $simplifier_sql->simplify($query);
97
if (defined $simplified_query) {
98
my $simplified_results = [];
100
foreach my $i (0,1) {
101
$simplified_results->[$i] =
102
$executors[$i]->execute($simplified_query, 1);
103
say("Simplified query".($i+1)." (".
104
$executors[$i]->getName()." ".
105
$executors[$i]->version()."): ".
106
$simplified_results->[$i]->query().";");
109
say(GenTest::Comparator::dumpDiff($simplified_results->[0], $simplified_results->[1]));
111
my $simplifier_test = GenTest::Simplifier::Test->new(
112
executors => \@executors ,
113
results => [ $simplified_results , \@results ]
115
# show_index is enabled for result difference queries its good to see the index details,
116
# the value 1 is used to define if show_index is enabled, to disable dont assign a value.
118
my $simplified_test = $simplifier_test->simplify($show_index);
120
my $tmpfile = tmpdir().$$.time().".test";
121
say("Dumping .test to $tmpfile");
122
open (TESTFILE, '>'.$tmpfile);
123
print TESTFILE $simplified_test;
126
say("Could not simplify failure, appears to be sporadic.");
132
my ($self, $executors, $results) = @_;
134
# Skip the whole stuff if only one resultset.
136
return STATUS_OK if $#$results < 1;
138
return STATUS_WONT_HANDLE
139
if $results->[0]->status() == STATUS_SEMANTIC_ERROR ||
140
$results->[1]->status() == STATUS_SEMANTIC_ERROR;
141
return STATUS_WONT_HANDLE if $results->[0]->query() =~ m{EXPLAIN}sio;
143
## Compare the two first resultsets
145
my $query = $results->[0]->query();
147
my $server1 = $executors->[0]->getName()." ".$executors->[0]->version();
148
my $server2 = $executors->[1]->getName()." ".$executors->[1]->version();
150
my $compare_1_2 = $self->compareTwo($query, $server1, $server2, $results->[0], $results->[1]);
151
my $compare_result = $compare_1_2;
153
# If 3 of them, do some more comparisions
155
if ($#$results > 1) {
156
my $server3 = $executors->[2]->getName()." ".$executors->[2]->version();
158
return STATUS_WONT_HANDLE if $results->[2]->status() == STATUS_SEMANTIC_ERROR;
160
my $compare_1_3 = $self->compareTwo($query, $server1, $server3, $results->[0], $results->[2]);
162
## If some of the above were different, we need compare 2 and
163
## 3 too to see if there exists a minority
164
if ($compare_1_2 > STATUS_OK or $compare_1_3 > STATUS_OK) {
166
return STATUS_WONT_HANDLE if $results->[2]->status() == STATUS_SEMANTIC_ERROR;
168
my $compare_2_3 = $self->compareTwo($query, $server2, $server3, $results->[1], $results->[2]);
170
if ($compare_1_2 > STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 > STATUS_OK) {
171
say("Minority report: no minority");
173
} elsif ($compare_1_2 > STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 == STATUS_OK) {
174
say("Minority report: $server1(dsn1) differs from the two others");
177
#### In this first shot, we only do simplification if
178
#### Server 1, which is assumed to be MySQL is the
179
#### minority, and we do the simplification only withe
180
#### excutions on 1 and 2. This should be sufficirnt
181
#### for hunting down MYSQL bugs.
183
if (($query =~ m{^\s*select}sio) && (
184
($compare_1_2 == STATUS_LENGTH_MISMATCH) ||
185
($compare_1_2 == STATUS_CONTENT_MISMATCH))) {
186
$self->simplifyTwo($query,$executors->[0],$executors->[1],$results->[0],$results->[1]);
188
} elsif ($compare_1_2 > STATUS_OK and $compare_1_3 == STATUS_OK and $compare_2_3 > STATUS_OK) {
189
say("Minority report: $server2(dsn2) differs from the two others");
191
} elsif ($compare_1_2 == STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 > STATUS_OK) {
192
say("Minority report: $server3(dsn3) differs from the two others");
196
$compare_result = $compare_2_3 if $compare_2_3 > $compare_result;
199
$compare_result = $compare_1_3 if $compare_1_3 > $compare_result;
204
# If the discrepancy is found on SELECT, we reduce the severity of
205
# the error so that the test can continue hopefully finding
206
# further errors in the same run or providing an indication as to
207
# how frequent the error is.
209
# If the discrepancy is on an UPDATE, then the servers have
210
# diverged and the test can not continue safely.
213
# CAVEAT: This may cause false positives if one execution
214
# influences the following executions. Failures due to a previous
215
# failure have been seen.
217
if ($query =~ m{^[\s/*!0-9]*(EXPLAIN|SELECT|ALTER|LOAD\s+INDEX|CACHE\s+INDEX)}io) {
218
return $compare_result - STATUS_SELECT_REDUCTION;
220
return $compare_result;