JoinTest.pm 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems(R).
  3. This program is free software: you can redistribute it and/or modify
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. package JoinTest;
  14. use strict;
  15. use warnings;
  16. use Exporter;
  17. our @ISA = qw(Exporter);
  18. our @EXPORT;
  19. our @activities = qw(JOIN DENORMALIZE DENORMALIZEGROUP);
  20. our @types = (0, qw(LOOKUP LOOKUP_MANY ALL));
  21. our @inouts = (0, map({my $a = $_; map({[$a, $_]} qw(OUTER ONLY))} qw(LEFT RIGHT FULL)));
  22. our @limits = (0, qw(KEEP ATMOST LIMITSKIP LIMITONFAIL LIMITFAIL));
  23. our @xfmskips = (0, 1);
  24. our @parallels = (0, 1);
  25. our @factors = ({name => 'activity', vals => \@JoinTest::activities},
  26. {name => 'type', vals => \@JoinTest::types},
  27. {name => 'inout', vals => \@JoinTest::inouts},
  28. {name => 'limit', vals => \@JoinTest::limits},
  29. {name => 'xfmskip', vals => \@JoinTest::xfmskips},
  30. {name => 'parallel', vals => \@JoinTest::parallels});
  31. my %_activitycodes = (JOIN => 'join', DENORMALIZE => 'deno', DENORMALIZEGROUP => 'dngr');
  32. my %_activitycommands = (JOIN => 'JOIN', DENORMALIZE => 'DENORMALIZE', DENORMALIZEGROUP => 'DENORMALIZE');
  33. my %_typecodes = (0 => '__', LOOKUP => 'l1', LOOKUP_MANY => 'lm', ALL => 'al');
  34. my %_limitcodes = (0 => '__', KEEP => 'kp', ATMOST => 'at', LIMITSKIP => 'ls', LIMITONFAIL => 'lo', LIMITFAIL => 'lf');
  35. my @_bads = ({type => 'LOOKUP', limit => 'KEEP'},
  36. {type => 'LOOKUP', limit => 'ATMOST'},
  37. {type => 'LOOKUP', limit => 'LIMITSKIP'},
  38. {type => 'LOOKUP', limit => 'LIMITONFAIL'},
  39. {type => 'LOOKUP', limit => 'LIMITFAIL'},
  40. {type => 'LOOKUP', inout => 'RIGHT_OUTER'},
  41. {type => 'LOOKUP', inout => 'RIGHT_ONLY'},
  42. {type => 'LOOKUP', inout => 'FULL_OUTER'},
  43. {type => 'LOOKUP', inout => 'FULL_ONLY'},
  44. {type => 'LOOKUP_MANY', inout => 'RIGHT_OUTER'},
  45. {type => 'LOOKUP_MANY', inout => 'RIGHT_ONLY'},
  46. {type => 'LOOKUP_MANY', inout => 'FULL_OUTER'},
  47. {type => 'LOOKUP_MANY', inout => 'FULL_ONLY'},
  48. {type => 'ALL', limit => 'ATMOST'},
  49. {type => 'ALL', limit => 'LIMITSKIP'},
  50. {type => 'ALL', limit => 'LIMITONFAIL'},
  51. {type => 'ALL', limit => 'LIMITFAIL'},
  52. {type => 'ALL', inout => 'RIGHT_OUTER'},
  53. {type => 'ALL', inout => 'RIGHT_ONLY'},
  54. {type => 'ALL', inout => 'FULL_OUTER'},
  55. {type => 'ALL', inout => 'FULL_ONLY'},
  56. {inout => 'RIGHT_OUTER', limit => 'KEEP'},
  57. {inout => 'RIGHT_OUTER', limit => 'ATMOST'},
  58. {inout => 'FULL_OUTER', limit => 'KEEP'},
  59. {inout => 'FULL_OUTER', limit => 'ATMOST'},
  60. {inout => 'LEFT_ONLY', limit => 'KEEP'},
  61. {inout => 'LEFT_ONLY', limit => 'LIMITSKIP'},
  62. {inout => 'LEFT_ONLY', limit => 'LIMITONFAIL'},
  63. {inout => 'LEFT_ONLY', limit => 'LIMITFAIL'},
  64. {inout => 'RIGHT_ONLY', limit => 'KEEP'},
  65. {inout => 'RIGHT_ONLY', limit => 'ATMOST'},
  66. {inout => 'RIGHT_ONLY', limit => 'LIMITSKIP'},
  67. {inout => 'RIGHT_ONLY', limit => 'LIMITONFAIL'},
  68. {inout => 'RIGHT_ONLY', limit => 'LIMITFAIL'},
  69. {inout => 'FULL_ONLY', limit => 'KEEP'},
  70. {inout => 'FULL_ONLY', limit => 'ATMOST'},
  71. {inout => 'FULL_ONLY', limit => 'LIMITSKIP'},
  72. {inout => 'FULL_ONLY', limit => 'LIMITONFAIL'},
  73. {inout => 'FULL_ONLY', limit => 'LIMITFAIL'},
  74. );
  75. my @_nothors = ({activity => 'DENORMALIZE', type => 'LOOKUP'},
  76. {activity => 'DENORMALIZE', type => 'LOOKUP_MANY'},
  77. {activity => 'DENORMALIZE', type => 'ALL'},
  78. {activity => 'DENORMALIZE', limit => 'ATMOST'},
  79. {activity => 'DENORMALIZE', limit => 'LIMITSKIP'},
  80. {activity => 'DENORMALIZE', limit => 'LIMITONFAIL'},
  81. {activity => 'DENORMALIZE', limit => 'LIMITFAIL'},
  82. {activity => 'DENORMALIZE', inout => 0},
  83. {activity => 'DENORMALIZE', inout => 'LEFT_ONLY'},
  84. {activity => 'DENORMALIZE', inout => 'RIGHT_OUTER'},
  85. {activity => 'DENORMALIZE', inout => 'RIGHT_ONLY'},
  86. {activity => 'DENORMALIZE', inout => 'FULL_OUTER'},
  87. {activity => 'DENORMALIZE', inout => 'FULL_ONLY'},
  88. {activity => 'DENORMALIZEGROUP'});
  89. sub new($% )
  90. {
  91. my ($class, %opts) = @_;
  92. my $self = \%opts;
  93. bless($self, $class);
  94. $self->_setdesc();
  95. $self->_setcode();
  96. $self->_setmatchxfm();
  97. return $self;
  98. }
  99. sub _setdesc($ )
  100. {
  101. my ($self) = @_;
  102. my @features = ($self->{activity});
  103. push(@features, $self->{type}) if($self->{type});
  104. push(@features, join('_', @{$self->{inout}})) if($self->{inout});
  105. push(@features, $self->{limit}) if($self->{limit});
  106. push(@features, 'XFMSKIP') if($self->{xfmskip});
  107. push(@features, 'PAR') if($self->{parallel});
  108. $self->{desc} = join('_', @features);
  109. }
  110. sub _actcode($ )
  111. {
  112. my ($self) = @_;
  113. my $ac = $_activitycodes{$self->{activity}} or die("unknown activity $self->{activity}");
  114. return $ac;
  115. }
  116. sub _typecode($ )
  117. {
  118. my ($self) = @_;
  119. my $tc = $_typecodes{$self->{type}} or die("unknown type $self->{type}");
  120. return $tc;
  121. }
  122. sub _inoutcode($ )
  123. {
  124. my ($self) = @_;
  125. return $self->{inout} ? (substr($self->{inout}->[0], 0, 1) . substr($self->{inout}->[1], 0, 2)) : 'INN';
  126. }
  127. sub _limitcode($ )
  128. {
  129. my ($self) = @_;
  130. my $lc = $_limitcodes{$self->{limit}} or die("unknown limit type $self->{limit}");
  131. return $lc;
  132. }
  133. sub _xfmcode($ )
  134. {
  135. my ($self) = @_;
  136. return ($self->{xfmskip} ? 'xs' : '__');
  137. }
  138. sub _parcode($ )
  139. {
  140. my ($self) = @_;
  141. return ($self->{parallel} ? 'p' : '_');
  142. }
  143. sub _setcode($ )
  144. {
  145. my ($self) = @_;
  146. my @features = ($self->_actcode(), $self->_typecode(), $self->_inoutcode(), $self->_limitcode(), $self->_xfmcode(), $self->_parcode());
  147. $self->{code} = join('_', @features);
  148. }
  149. sub _setmatchxfm($ )
  150. {
  151. my ($self) = @_;
  152. $self->{matcharg} = ($self->{type} eq 'ALL') ? 'allmatch' : 'match';
  153. $self->{xfmarg} = 'xfm';
  154. my $xfmrightarg := 'RIGHT';
  155. if($self->{activity} eq 'DENORMALIZEGROUP')
  156. {
  157. $self->{xfmarg} .= 'grp';
  158. $xfmrightarg = 'ROWS(RIGHT)';
  159. }
  160. if($self->{xfmskip})
  161. {
  162. $self->{matcharg} .= '1';
  163. $self->{xfmarg} .= 'skip';
  164. }
  165. $self->{matcharg} .= '(LEFT, RIGHT)';
  166. $self->{xfmarg} .= "(LEFT, $xfmrightarg, '$self->{desc}')";
  167. }
  168. sub _matchesConditions($$ )
  169. {
  170. my ($self, $conds) = @_;
  171. foreach my $cond (keys(%$conds))
  172. {
  173. my $val = $self->{$cond};
  174. $val = join('_', @$val) if(ref($val));
  175. return 0 unless($val eq $conds->{$cond});
  176. }
  177. return 1;
  178. }
  179. sub forbidden($ )
  180. {
  181. my ($self) = @_;
  182. foreach my $bad (@_bads)
  183. {
  184. return 1 if($self->_matchesConditions($bad));
  185. }
  186. return 0;
  187. }
  188. sub nothor($ )
  189. {
  190. my ($self) = @_;
  191. foreach my $nothor (@_nothors)
  192. {
  193. return 1 if($self->_matchesConditions($nothor));
  194. }
  195. return 0;
  196. }
  197. sub justroxie($ )
  198. {
  199. my ($self) = @_;
  200. return $self->{parallel};
  201. }
  202. sub fails($ )
  203. {
  204. my ($self) = @_;
  205. return ($self->{limit} eq 'LIMITFAIL');
  206. }
  207. sub _limitargs($ )
  208. {
  209. my ($self) = @_;
  210. return("KEEP($self->{keepval})"), if($self->{limit} eq 'KEEP');
  211. return("ATMOST(match1(LEFT, RIGHT), $self->{limitval})"), if($self->{limit} eq 'ATMOST');
  212. return("LIMIT($self->{limitval}, SKIP)", "ONFAIL(xfm(LEFT, RIGHT, 'FAILED: $self->{desc}'))"), if($self->{limit} eq 'LIMITSKIP');
  213. return("LIMIT($self->{limitval})", "ONFAIL(xfm(LEFT, RIGHT, 'FAILED: $self->{desc}'))"), if($self->{limit} eq 'LIMITONFAIL');
  214. return("LIMIT($self->{limitval})"), if($self->{limit} eq 'LIMITFAIL');
  215. die("unknown limit type $self->{limit}");
  216. }
  217. sub _args($ )
  218. {
  219. my ($self) = @_;
  220. my @args = ('lhs', 'rhs', "$self->{matcharg}");
  221. push(@args, 'GROUP') if($self->{activity} eq 'DENORMALIZEGROUP');
  222. push(@args, "$self->{xfmarg}");
  223. push(@args, split(/_/, $self->{type})) if($self->{type});
  224. push(@args, ($self->{inout} ? join(' ', @{$self->{inout}}) : 'INNER'));
  225. push(@args, $self->_limitargs()) if($self->{limit});
  226. push(@args, 'PARALLEL') if($self->{parallel});
  227. return join(', ', @args);
  228. }
  229. sub defecl($ )
  230. {
  231. my ($self) = @_;
  232. my $actcmd = $_activitycommands{$self->{activity}};
  233. my $args = $self->_args();
  234. return("$self->{code} := $actcmd($args)");
  235. }
  236. sub outecl($ )
  237. {
  238. my ($self) = @_;
  239. return("OUTPUT($self->{code}, NAMED('$self->{desc}'))");
  240. }
  241. 1;