1
# 2-way and 3-way result set comparartor with minority report in the
2
# case of 3-way comparision. Does also the same job as
3
# ResultsetComparator and may replace it for 2-ay comparision.
5
package GenTest::Validator::ResultsetComparator3Simplify;
8
@ISA = qw(GenTest GenTest::Validator);
13
use GenTest::Constants;
14
use GenTest::Comparator;
16
use GenTest::Validator;
17
use GenTest::Simplifier::SQL;
18
use GenTest::Simplifier::Test;
22
my ($self, $q, $s1, $s2, $res1, $res2) = @_;
24
my $outcome = GenTest::Comparator::compare($res1, $res2);
26
if ($outcome == STATUS_LENGTH_MISMATCH) {
27
if ($q =~ m{^\s*select}io) {
29
say("Result length mismatch between $s1 and $s2 (".$res1->rows()." vs. ".$res2->rows().")");
30
say("Query1: " . $res1->query());
31
say("Query2: " . $res2->query());
32
say(GenTest::Comparator::dumpDiff($res1,$res2));
35
say("Affected_rows mismatch between $s1 and $s2 (".$res1->affectedRows()." vs. ".$res2->affectedRows().")");
36
say("Query1: " . $res1->query());
37
say("Query2: " . $res2->query());
39
} elsif ($outcome == STATUS_CONTENT_MISMATCH) {
41
say("Result content mismatch between $s1 and $s2.");
42
say("Query1: " . $res1->query());
43
say("Query2: " . $res2->query());
44
say(GenTest::Comparator::dumpDiff($res1, $res2));
52
my ($self, $query, $ex1, $ex2, $r1, $r2) = @_;
54
my @executors = ( $ex1, $ex2 );
56
my @results = ($r1, $r2);
58
my $simplifier_sql = GenTest::Simplifier::SQL->new(
60
my $oracle_query = shift;
63
foreach my $executor (@executors) {
64
push @oracle_results, $executor->execute($oracle_query, 1);
66
my $oracle_compare = GenTest::Comparator::compare($oracle_results[0], $oracle_results[1]);
68
($oracle_compare == STATUS_LENGTH_MISMATCH) ||
69
($oracle_compare == STATUS_CONTENT_MISMATCH)
71
return ORACLE_ISSUE_STILL_REPEATABLE;
73
return ORACLE_ISSUE_NO_LONGER_REPEATABLE;
78
my $simplified_query = $simplifier_sql->simplify($query);
80
if (defined $simplified_query) {
81
my $simplified_results = [];
84
$simplified_results->[$i] =
85
$executors[$i]->execute($simplified_query, 1);
86
say("Simplified query".($i+1)." (".
87
$executors[$i]->getName()." ".
88
$executors[$i]->version()."): ".
89
$simplified_results->[$i]->query().";");
92
say(GenTest::Comparator::dumpDiff($simplified_results->[0], $simplified_results->[1]));
94
my $simplifier_test = GenTest::Simplifier::Test->new(
95
executors => \@executors ,
96
results => [ $simplified_results , \@results ]
99
my $simplified_test = $simplifier_test->simplify();
101
my $tmpfile = tmpdir().$$.time().".test";
102
say("Dumping .test to $tmpfile");
103
open (TESTFILE, '>'.$tmpfile);
104
print TESTFILE $simplified_test;
107
say("Could not simplify failure, appears to be sporadic.");
113
my ($self, $executors, $results) = @_;
115
# Skip the whole stuff if only one resultset.
117
return STATUS_OK if $#$results < 1;
119
return STATUS_WONT_HANDLE
120
if $results->[0]->status() == STATUS_SEMANTIC_ERROR ||
121
$results->[1]->status() == STATUS_SEMANTIC_ERROR;
122
return STATUS_WONT_HANDLE if $results->[0]->query() =~ m{EXPLAIN}sio;
124
## Compare the two first resultsets
126
my $query = $results->[0]->query();
128
my $server1 = $executors->[0]->getName()." ".$executors->[0]->version();
129
my $server2 = $executors->[1]->getName()." ".$executors->[1]->version();
131
my $compare_1_2 = $self->compareTwo($query, $server1, $server2, $results->[0], $results->[1]);
132
my $compare_result = $compare_1_2;
134
# If 3 of them, do some more comparisions
136
if ($#$results > 1) {
137
my $server3 = $executors->[2]->getName()." ".$executors->[2]->version();
139
return STATUS_WONT_HANDLE if $results->[2]->status() == STATUS_SEMANTIC_ERROR;
141
my $compare_1_3 = $self->compareTwo($query, $server1, $server3, $results->[0], $results->[2]);
143
## If some of the above were different, we need compare 2 and
144
## 3 too to see if there exists a minority
145
if ($compare_1_2 > STATUS_OK or $compare_1_3 > STATUS_OK) {
147
return STATUS_WONT_HANDLE if $results->[2]->status() == STATUS_SEMANTIC_ERROR;
149
my $compare_2_3 = $self->compareTwo($query, $server2, $server3, $results->[1], $results->[2]);
151
if ($compare_1_2 > STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 > STATUS_OK) {
152
say("Minority report: no minority");
154
} elsif ($compare_1_2 > STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 == STATUS_OK) {
155
say("Minority report: $server1(dsn1) differs from the two others");
158
#### In this first shot, we only do simplification if
159
#### Server 1, which is assumed to be MySQL is the
160
#### minority, and we do the simplification only withe
161
#### excutions on 1 and 2. This should be sufficirnt
162
#### for hunting down MYSQL bugs.
164
if (($query =~ m{^\s*select}sio) && (
165
($compare_1_2 == STATUS_LENGTH_MISMATCH) ||
166
($compare_1_2 == STATUS_CONTENT_MISMATCH))) {
167
$self->simplifyTwo($query,$executors->[0],$executors->[1],$results->[0],$results->[1]);
169
} elsif ($compare_1_2 > STATUS_OK and $compare_1_3 == STATUS_OK and $compare_2_3 > STATUS_OK) {
170
say("Minority report: $server2(dsn2) differs from the two others");
172
} elsif ($compare_1_2 == STATUS_OK and $compare_1_3 > STATUS_OK and $compare_2_3 > STATUS_OK) {
173
say("Minority report: $server3(dsn3) differs from the two others");
177
$compare_result = $compare_2_3 if $compare_2_3 > $compare_result;
180
$compare_result = $compare_1_3 if $compare_1_3 > $compare_result;
185
# If the discrepancy is found on SELECT, we reduce the severity of
186
# the error so that the test can continue hopefully finding
187
# further errors in the same run or providing an indication as to
188
# how frequent the error is.
190
# If the discrepancy is on an UPDATE, then the servers have
191
# diverged and the test can not continue safely.
194
# CAVEAT: This may cause false positives if one execution
195
# influences the following executions. Failures due to a previous
196
# failure have been seen.
198
if ($query =~ m{^[\s/*!0-9]*(EXPLAIN|SELECT|ALTER|LOAD\s+INDEX|CACHE\s+INDEX)}io) {
199
return $compare_result - STATUS_SELECT_REDUCTION;
201
return $compare_result;