~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to tests/kewpie/randgen/lib/GenTest/Transform.pm

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-06-19 10:46:49 UTC
  • mfrom: (1.1.6)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20120619104649-e2l0ggd4oz3um0f4
Tags: upstream-7.1.36-stable
ImportĀ upstreamĀ versionĀ 7.1.36-stable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2008,2011 Oracle and/or its affiliates. All rights reserved.
 
2
# Use is subject to license terms.
 
3
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
# USA
 
17
 
 
18
package GenTest::Transform;
 
19
 
 
20
require Exporter;
 
21
@ISA = qw(GenTest);
 
22
 
 
23
use strict;
 
24
 
 
25
use lib 'lib';
 
26
use GenTest;
 
27
use GenTest::Constants;
 
28
use GenTest::Executor::MySQL;
 
29
use Data::Dumper;
 
30
 
 
31
use constant TRANSFORMER_QUERIES_PROCESSED      => 0;
 
32
use constant TRANSFORMER_QUERIES_TRANSFORMED    => 1;
 
33
 
 
34
use constant TRANSFORM_OUTCOME_EXACT_MATCH      => 1001;
 
35
use constant TRANSFORM_OUTCOME_UNORDERED_MATCH  => 1002;
 
36
use constant TRANSFORM_OUTCOME_SUPERSET         => 1003;
 
37
use constant TRANSFORM_OUTCOME_SUBSET           => 1004;
 
38
use constant TRANSFORM_OUTCOME_SINGLE_ROW       => 1005;
 
39
use constant TRANSFORM_OUTCOME_FIRST_ROW        => 1006;
 
40
use constant TRANSFORM_OUTCOME_DISTINCT         => 1007;
 
41
use constant TRANSFORM_OUTCOME_COUNT            => 1008;
 
42
use constant TRANSFORM_OUTCOME_EMPTY_RESULT     => 1009;
 
43
use constant TRANSFORM_OUTCOME_SINGLE_INTEGER_ONE       => 1010;
 
44
 
 
45
my %transform_outcomes = (
 
46
        'TRANSFORM_OUTCOME_EXACT_MATCH'         => 1001,
 
47
        'TRANSFORM_OUTCOME_UNORDERED_MATCH'     => 1002,
 
48
        'TRANSFORM_OUTCOME_SUPERSET'            => 1003,
 
49
        'TRANSFORM_OUTCOME_SUBSET'              => 1004,
 
50
        'TRANSFORM_OUTCOME_SINGLE_ROW'          => 1005,
 
51
        'TRANSFORM_OUTCOME_FIRST_ROW'           => 1006,
 
52
        'TRANSFORM_OUTCOME_DISTINCT'            => 1007,
 
53
        'TRANSFORM_OUTCOME_COUNT'               => 1008,
 
54
        'TRANSFORM_OUTCOME_EMPTY_RESULT'        => 1009,
 
55
        'TRANSFORM_OUTCOME_SINGLE_INTEGER_ONE'  => 1010
 
56
);
 
57
 
 
58
# Subset of semantic errors that we may want to allow during transforms.
 
59
my %mysql_grouping_errors = (
 
60
        1004 => 'ER_NON_GROUPING_FIELD_USED',
 
61
        1055 => 'ER_WRONG_FIELD_WITH_GROUP',
 
62
        1056 => 'ER_WRONG_GROUP_FIELD',
 
63
        1140 => 'ER_MIX_OF_GROUP_FUNC_AND_FIELDS',
 
64
        1317 => 'ER_QUERY_INTERRUPTED',
 
65
        2013 => 'CR_SERVER_LOST',
 
66
        2006 => 'CR_SERVER_GONE_ERROR',
 
67
        1028 => 'ER_FILSORT_ABORT',
 
68
        1111 => 'ER_INVALID_GROUP_FUNC_USE',
 
69
        1615 => 'ER_NEED_REPREPARE',
 
70
        1060 => 'DUPLICATE_COLUMN_NAME',
 
71
        1104 => 'ER_TOO_BIG_SELECT'
 
72
);
 
73
 
 
74
# List of encountered errors that we want to suppress later in the test run.
 
75
my %suppressed_errors = ();
 
76
 
 
77
sub transformExecuteValidate {
 
78
        my ($transformer, $original_query, $original_result, $executor) = @_;
 
79
 
 
80
        $transformer->[TRANSFORMER_QUERIES_PROCESSED]++;
 
81
 
 
82
        my $transformer_output = $transformer->transform($original_query, $executor, $original_result);
 
83
 
 
84
        my $transform_blocks;
 
85
 
 
86
        if ($transformer_output =~ m{^\d+$}sgio) {
 
87
                if ($transformer_output == STATUS_WONT_HANDLE) {
 
88
                        return STATUS_OK;
 
89
                } else {
 
90
                        return $transformer_output;     # Error was returned and no queries
 
91
                }
 
92
        } elsif (ref($transformer_output) eq 'ARRAY') {
 
93
                if (ref($transformer_output->[0]) eq 'ARRAY') {
 
94
                        # Transformation produced more than one block of queries
 
95
                        $transform_blocks = $transformer_output;
 
96
                } else {
 
97
                        # Transformation produced a single block of queries
 
98
                        $transform_blocks = [ $transformer_output ];
 
99
                }       
 
100
        } else {
 
101
                # Transformation produced a single query, convert it to a single block
 
102
                $transform_blocks = [ [ $transformer_output ] ];
 
103
        }
 
104
 
 
105
        foreach my $transform_block (@$transform_blocks) {
 
106
                my @transformed_queries = @$transform_block;
 
107
                my @transformed_results;
 
108
                my $transform_outcome;
 
109
        
 
110
                $transformed_queries[0] =  "/* ".ref($transformer)." */ ".$transformed_queries[0];
 
111
 
 
112
                foreach my $transformed_query_part (@transformed_queries) {
 
113
                        my $part_result = $executor->execute($transformed_query_part);
 
114
 
 
115
                        if ($part_result->status() == STATUS_SKIP) {
 
116
                                $transform_outcome = STATUS_OK;
 
117
                                next;
 
118
                        } elsif (
 
119
                                ($part_result->status() == STATUS_SYNTAX_ERROR) || 
 
120
                                ($part_result->status() == STATUS_SEMANTIC_ERROR) ||
 
121
                                ($part_result->status() == STATUS_SERVER_CRASHED) 
 
122
                        ) {
 
123
                                # We normally return a critical error when a transformer returns
 
124
                                # a semantic or syntactic error, because we want to detect any
 
125
                                # faulty transformers, e.g. those which do not produce valid 
 
126
                                # queries. However, some errors may need to be accepted in
 
127
                                # certain situations.
 
128
                                #
 
129
                                # For example, with MySQL's ONLY_FULL_GROUP_BY sql mode, some
 
130
                                # queries return grouping related errors, whereas they would
 
131
                                # not return such errors without this mode, and we want to 
 
132
                                # continue the test even if such errors occur.
 
133
                                # We have logic in place to take care of this below.
 
134
                                #
 
135
                                if ( 
 
136
                                        ($executor->type() == DB_MYSQL) && 
 
137
                                        (exists $mysql_grouping_errors{$part_result->err()}) 
 
138
                                ){
 
139
                                        if (rqg_debug()) {
 
140
                                                say("Ignoring transform ".ref($transformer)." that failed with the error: ".$part_result->errstr());
 
141
                                                say("Offending query is: $transformed_query_part;");
 
142
                                        } else {
 
143
                                                if (not defined $suppressed_errors{$part_result->err()}) {
 
144
                                                        say("Ignoring transforms of the type ".ref($transformer)." that fail with an error like: ".$part_result->errstr());
 
145
                                                        $suppressed_errors{$part_result->err()}++;
 
146
                                                }
 
147
                                        }
 
148
                                        # Then move on...
 
149
                                        # We "cheat" by returning STATUS_OK, as the validator would otherwise try to access the result.
 
150
                                        return STATUS_OK;
 
151
                                }
 
152
                                say("---------- TRANSFORM ISSUE ----------");
 
153
                                say("Transform ".ref($transformer)." failed with a syntactic or semantic error: ".$part_result->err()." ".$part_result->errstr().
 
154
                                        "; RQG Status: ".status2text($part_result->status())." (".$part_result->status().")");
 
155
                                say("Offending query is: $transformed_query_part;");
 
156
                                say("Original query is: $original_query;");
 
157
                                say("ERROR: Possible syntax or semantic error caused by code in transformer ".ref($transformer).
 
158
                                        ". Raising severity to STATUS_ENVIRONMENT_FAILURE.");
 
159
                                return STATUS_ENVIRONMENT_FAILURE;
 
160
                        } elsif ($part_result->status() != STATUS_OK) {
 
161
                                say("---------- TRANSFORM ISSUE ----------");
 
162
                                say("Transform ".$transformer->name()." failed with an error: ".$part_result->err().'  '.$part_result->errstr());
 
163
                                say("Transformed query was: ".$transformed_query_part);
 
164
                                return $part_result->status();
 
165
                        } elsif (defined $part_result->data()) {
 
166
                                my $part_outcome = $transformer->validate($original_result, $part_result);
 
167
                                $transform_outcome = $part_outcome if (($part_outcome > $transform_outcome) || (! defined $transform_outcome));
 
168
                                push @transformed_results, $part_result if ($part_outcome != STATUS_WONT_HANDLE) && ($part_outcome != STATUS_OK);
 
169
                        }
 
170
                }
 
171
 
 
172
                if (
 
173
                        (not defined $transform_outcome) ||
 
174
                        ($transform_outcome == STATUS_WONT_HANDLE)
 
175
                ) {
 
176
                        say("Transform ".ref($transformer)." produced no query which could be validated ($transform_outcome).");
 
177
                        say("The following queries were produced");
 
178
                        print Dumper \@transformed_queries;
 
179
                        return STATUS_ENVIRONMENT_FAILURE;
 
180
                }
 
181
 
 
182
                $transformer->[TRANSFORMER_QUERIES_TRANSFORMED]++;
 
183
 
 
184
                if ($transform_outcome != STATUS_OK) {
 
185
                        return ($transform_outcome, \@transformed_queries, \@transformed_results);
 
186
                }
 
187
        }
 
188
        
 
189
        return STATUS_OK;
 
190
 
 
191
}
 
192
 
 
193
sub validate {
 
194
        my ($transformer, $original_result, $transformed_result) = @_;
 
195
 
 
196
        my $transformed_query = $transformed_result->query();
 
197
 
 
198
        my $transform_outcome;
 
199
 
 
200
        foreach my $potential_outcome (keys %transform_outcomes) {
 
201
                if ($transformed_query =~ m{$potential_outcome}s) {
 
202
                        $transform_outcome = $transform_outcomes{$potential_outcome};
 
203
                        last;
 
204
                }
 
205
        }
 
206
 
 
207
        if ($transform_outcome == TRANSFORM_OUTCOME_SINGLE_ROW) {
 
208
                return $transformer->isSingleRow($original_result, $transformed_result);
 
209
        } elsif ($transform_outcome == TRANSFORM_OUTCOME_DISTINCT) {
 
210
                return $transformer->isDistinct($original_result, $transformed_result);
 
211
        } elsif ($transform_outcome == TRANSFORM_OUTCOME_UNORDERED_MATCH) {
 
212
                return GenTest::Comparator::compare($original_result, $transformed_result);
 
213
        } elsif ($transform_outcome == TRANSFORM_OUTCOME_SUPERSET) {
 
214
                return $transformer->isSuperset($original_result, $transformed_result);
 
215
        } elsif ($transform_outcome == TRANSFORM_OUTCOME_FIRST_ROW) {
 
216
                return $transformer->isFirstRow($original_result, $transformed_result);
 
217
        } elsif ($transform_outcome == TRANSFORM_OUTCOME_COUNT) {
 
218
                return $transformer->isCount($original_result, $transformed_result);
 
219
        } elsif ($transform_outcome == TRANSFORM_OUTCOME_EMPTY_RESULT) {
 
220
                return $transformer->isEmptyResult($original_result, $transformed_result);
 
221
        } elsif ($transform_outcome == TRANSFORM_OUTCOME_SINGLE_INTEGER_ONE) {
 
222
                return $transformer->isSingleIntegerOne($original_result, $transformed_result);
 
223
        } else {
 
224
                return STATUS_WONT_HANDLE;
 
225
        }
 
226
}
 
227
 
 
228
sub isFirstRow {
 
229
        my ($transformer, $original_result, $transformed_result) = @_;
 
230
 
 
231
        if (
 
232
                ($original_result->rows() == 0) &&
 
233
                ($transformed_result->rows() == 0)
 
234
        ) {
 
235
                return STATUS_OK;
 
236
        } else {
 
237
                my $row1 = join('<col>', @{$original_result->data()->[0]});
 
238
                my $row2 = join('<col>', @{$transformed_result->data()->[0]});
 
239
                return STATUS_CONTENT_MISMATCH if $row1 ne $row2;
 
240
        }
 
241
        return STATUS_OK;
 
242
}
 
243
 
 
244
sub isDistinct {
 
245
        my ($transformer, $original_result, $transformed_result) = @_;
 
246
 
 
247
        my $original_rows;
 
248
        my $transformed_rows;
 
249
 
 
250
        foreach my $row_ref (@{$original_result->data()}) {
 
251
                my $row = lc(join('<col>', @$row_ref));
 
252
                $original_rows->{$row}++;
 
253
        }
 
254
 
 
255
        foreach my $row_ref (@{$transformed_result->data()}) {
 
256
                my $row = lc(join('<col>', @$row_ref));
 
257
                $transformed_rows->{$row}++;
 
258
                return STATUS_LENGTH_MISMATCH if $transformed_rows->{$row} > 1;
 
259
        }
 
260
 
 
261
 
 
262
        my $distinct_original = join ('<row>', sort keys %{$original_rows} );
 
263
        my $distinct_transformed = join ('<row>', sort keys %{$transformed_rows} );
 
264
 
 
265
        if ($distinct_original ne $distinct_transformed) {
 
266
                return STATUS_CONTENT_MISMATCH;
 
267
        } else {
 
268
                return STATUS_OK;
 
269
        }
 
270
}
 
271
 
 
272
sub isSuperset {
 
273
        my ($transformer, $original_result, $transformed_result) = @_;
 
274
        my %rows;
 
275
 
 
276
        foreach my $row_ref (@{$original_result->data()}) {
 
277
                my $row = join('<col>', @$row_ref);
 
278
                $rows{$row}++;
 
279
        }
 
280
 
 
281
        foreach my $row_ref (@{$transformed_result->data()}) {
 
282
                my $row = join('<col>', @$row_ref);
 
283
                $rows{$row}--;
 
284
        }
 
285
 
 
286
        foreach my $row (keys %rows) {
 
287
                return STATUS_LENGTH_MISMATCH if $rows{$row} > 0;
 
288
        }
 
289
 
 
290
        return STATUS_OK;
 
291
}
 
292
 
 
293
sub isSingleRow {
 
294
        my ($transformer, $original_result, $transformed_result) = @_;
 
295
 
 
296
        if (
 
297
                ($original_result->rows() == 0) &&
 
298
                ($transformed_result->rows() == 0)
 
299
        ) {
 
300
                return STATUS_OK;
 
301
        } elsif ($transformed_result->rows() == 1) {
 
302
                my $transformed_row = join('<col>', @{$transformed_result->data()->[0]});
 
303
                foreach my $original_row_ref (@{$original_result->data()}) {
 
304
                        my $original_row = join('<col>', @$original_row_ref);
 
305
                        return STATUS_OK if $original_row eq $transformed_row;
 
306
                }
 
307
                return STATUS_CONTENT_MISMATCH;
 
308
        } else {
 
309
                # More than one row, something is messed up
 
310
                return STATUS_LENGTH_MISMATCH;
 
311
        }
 
312
}
 
313
 
 
314
sub isCount {
 
315
        my ($transformer, $original_result, $transformed_result) = @_;
 
316
 
 
317
        my ($large_result, $small_result) ;
 
318
 
 
319
        if (
 
320
                ($original_result->rows() == 0) ||
 
321
                ($transformed_result->rows() == 0)
 
322
        ) {
 
323
                return STATUS_OK;
 
324
        } elsif (
 
325
                ($original_result->rows() == 1) &&
 
326
                ($transformed_result->rows() == 1)
 
327
        ) {
 
328
                return STATUS_OK;
 
329
        } elsif (
 
330
                ($original_result->rows() == 1) &&
 
331
                ($transformed_result->rows() >= 1)
 
332
        ) {
 
333
                $small_result = $original_result;
 
334
                $large_result = $transformed_result;
 
335
        } elsif (
 
336
                ($transformed_result->rows() == 1) &&
 
337
                ($original_result->rows() >= 1)
 
338
        ) {
 
339
                $small_result = $transformed_result;
 
340
                $large_result = $original_result;
 
341
        } else {
 
342
                return STATUS_LENGTH_MISMATCH;
 
343
        }
 
344
 
 
345
        if ($large_result->rows() != $small_result->data()->[0]->[0]) {
 
346
                return STATUS_LENGTH_MISMATCH;
 
347
        } else {
 
348
                return STATUS_OK;
 
349
        }
 
350
}
 
351
 
 
352
sub isEmptyResult {
 
353
        my ($transformer, $original_result, $transformed_result) = @_;
 
354
 
 
355
        if ($transformed_result->rows() == 0) {
 
356
                return STATUS_OK;
 
357
        } else {
 
358
                return STATUS_LENGTH_MISMATCH;
 
359
        }
 
360
}
 
361
 
 
362
sub isSingleIntegerOne {
 
363
        my ($transformer, $original_result, $transformed_result) = @_;
 
364
 
 
365
        if (
 
366
                ($transformed_result->rows() == 1) &&
 
367
                ($#{$transformed_result->data()->[0]} == 0) &&
 
368
                ($transformed_result->data()->[0]->[0] eq '1')
 
369
        ) {
 
370
                return STATUS_OK;
 
371
        } else {
 
372
                return STATUS_LENGTH_MISMATCH;
 
373
        }
 
374
 
 
375
 
 
376
}
 
377
 
 
378
sub name {
 
379
        my $transformer = shift;
 
380
        my ($name) = $transformer =~ m{.*::([a-z]*)}sgio;
 
381
        return $name;
 
382
}
 
383
 
 
384
sub DESTROY {
 
385
        my $transformer = shift;
 
386
        print "# ".ref($transformer).": queries_processed: ".$transformer->[TRANSFORMER_QUERIES_PROCESSED]."; queries_transformed: ".$transformer->[TRANSFORMER_QUERIES_TRANSFORMED]."\n" if rqg_debug();
 
387
}
 
388
 
 
389
1;