1
# Copyright (c) 2008, 2011 Oracle and/or its affiliates. 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
package GenTest::Validator::ResultsetComparatorSimplify;
21
@ISA = qw(GenTest GenTest::Validator);
26
use GenTest::Constants;
27
use GenTest::Comparator;
29
use GenTest::Validator;
30
use GenTest::Executor::MySQL;
31
use GenTest::Simplifier::SQL;
32
use GenTest::Simplifier::Test;
36
use DBIx::MyParsePP::Rule;
38
my $empty_child = DBIx::MyParsePP::Rule->new();
39
my $myparse = DBIx::MyParsePP->new();
43
my ($comparator, $executors, $results) = @_;
45
return STATUS_WONT_HANDLE if $#$results != 1;
47
return STATUS_WONT_HANDLE if $results->[0]->query() =~ m{EXPLAIN}sio;
49
if ( $results->[0]->err() != $results->[1]->err() ) {
50
say("Query: ".$results->[0]->query()."; failed: error code mismatch between servers ('".$results->[0]->errstr()."' vs. '".$results->[1]->errstr()."')");
51
return STATUS_ERROR_MISMATCH;
54
return STATUS_WONT_HANDLE if $results->[0]->status() != STATUS_OK;
55
return STATUS_WONT_HANDLE if $results->[1]->status() != STATUS_OK;
57
return STATUS_WONT_HANDLE if defined $results->[0]->warnings();
58
return STATUS_WONT_HANDLE if defined $results->[1]->warnings();
60
my $query = $results->[0]->query();
61
my $compare_outcome = GenTest::Comparator::compare($results->[0], $results->[1]);
63
if ( ($compare_outcome == STATUS_LENGTH_MISMATCH) ||
64
($compare_outcome == STATUS_CONTENT_MISMATCH)
66
say("---------- RESULT COMPARISON ISSUE START ----------");
69
if ($compare_outcome == STATUS_LENGTH_MISMATCH) {
70
if ($query =~ m{^\s*select}io) {
71
say("Query: $query; failed: result length mismatch between servers (".$results->[0]->rows()." vs. ".$results->[1]->rows().")");
72
say(GenTest::Comparator::dumpDiff($results->[0], $results->[1]));
74
say("Query: $query; failed: affected_rows mismatch between servers (".$results->[0]->affectedRows()." vs. ".$results->[1]->affectedRows().")");
76
} elsif ($compare_outcome == STATUS_CONTENT_MISMATCH) {
77
say("Query: $query; failed: result content mismatch between servers.");
78
say(GenTest::Comparator::dumpDiff($results->[0], $results->[1]));
82
($query =~ m{^\s*select}sio) && (
83
($compare_outcome == STATUS_LENGTH_MISMATCH) ||
84
($compare_outcome == STATUS_CONTENT_MISMATCH)
87
my $simplifier_sql = GenTest::Simplifier::SQL->new(
89
my $oracle_query = shift;
92
foreach my $executor (@$executors) {
93
my $oracle_result = $executor->execute($oracle_query, 1);
95
return ORACLE_ISSUE_STATUS_UNKNOWN if $oracle_result->status() != STATUS_OK;
96
return ORACLE_ISSUE_STATUS_UNKNOWN if defined $oracle_result->warnings();
98
push @oracle_results, $oracle_result;
101
my $oracle_compare = GenTest::Comparator::compare($oracle_results[0], $oracle_results[1]);
104
# If both result sets are empty, we can not decide if the issue continues to be repeatable
105
# or not. So, to be safe, we return "unknown", otherwise we risk messing up the differential
109
if (($oracle_results[0]->rows() == 0) && ($oracle_results[1]->rows() == 0)) {
110
return ORACLE_ISSUE_STATUS_UNKNOWN;
112
($oracle_compare == STATUS_LENGTH_MISMATCH) ||
113
($oracle_compare == STATUS_CONTENT_MISMATCH)
115
return ORACLE_ISSUE_STILL_REPEATABLE;
117
return ORACLE_ISSUE_NO_LONGER_REPEATABLE;
122
my $simplified_query = $simplifier_sql->simplify($query);
124
if (defined $simplified_query) {
125
say("Simplified query: $simplified_query;");
128
$executors->[0]->execute("EXPLAIN ".$simplified_query),
129
$executors->[1]->execute("EXPLAIN ".$simplified_query)
131
say("EXPLAIN diff:");
132
say(GenTest::Comparator::dumpDiff(@explains));
134
my $simplified_results = [];
135
$simplified_results->[0] = $executors->[0]->execute($simplified_query, 1);
136
$simplified_results->[1] = $executors->[1]->execute($simplified_query, 1);
137
say("Result set diff:");
138
say(GenTest::Comparator::dumpDiff($simplified_results->[0], $simplified_results->[1]));
140
my $simplifier_test = GenTest::Simplifier::Test->new(
141
executors => $executors,
142
results => [ $simplified_results , $results ]
144
# show_index is enabled for result difference queries its good to see the index details,
145
# the value 1 is used to define if show_index is enabled, to disable dont assign a value.
147
my $simplified_test = $simplifier_test->simplify($show_index);
149
my $tmpfile = tmpdir().$$.time().".test";
150
say("Dumping .test to $tmpfile");
151
open (TESTFILE, '>'.$tmpfile);
152
print TESTFILE $simplified_test;
155
say("Could not simplify failure, appears to be sporadic.");
159
if ( ($compare_outcome == STATUS_LENGTH_MISMATCH) ||
160
($compare_outcome == STATUS_CONTENT_MISMATCH)
162
say("---------- RESULT COMPARISON ISSUE END ------------");
166
# If the discrepancy is found on SELECT, we reduce the severity of the error so that the test can continue
167
# hopefully finding further errors in the same run or providing an indication as to how frequent the error is
169
# If the discrepancy is on an UPDATE, then the servers have diverged and the test can not continue safely.
172
if ($query =~ m{^[\s/*!0-9]*(EXPLAIN|SELECT|ALTER|LOAD\s+INDEX|CACHE\s+INDEX)}io) {
173
return $compare_outcome - STATUS_SELECT_REDUCTION;
175
return $compare_outcome;