~xnox/ubuntu/saucy/drizzle/merge

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-06-19 10:46:49 UTC
  • mfrom: (1.2.11) (2.1.16 sid)
  • Revision ID: package-import@ubuntu.com-20120619104649-9ij634mxm4x8pp4l
Tags: 1:7.1.36-stable-1ubuntu1
* Merge from Debian unstable. (LP: #987575)
  Remaining changes:
  - Added upstart script.
* debian/drizzle.upstart: dropped logger since upstart logs job
  output now.

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