JoinTest.pm 9.1 KB

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