Drizzled Public API Documentation

sel_arg.h
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #pragma once
00021 
00022 namespace drizzled {
00023 namespace optimizer {
00024 
00025 /*
00026   A construction block of the SEL_ARG-graph.
00027 
00028   The following description only covers graphs of SEL_ARG objects with
00029   sel_arg->type==KEY_RANGE:
00030 
00031   One SEL_ARG object represents an "elementary interval" in form
00032 
00033       min_value <=?  table.keypartX  <=? max_value
00034 
00035   The interval is a non-empty interval of any kind: with[out] minimum/maximum
00036   bound, [half]open/closed, single-point interval, etc.
00037 
00038   1. SEL_ARG GRAPH STRUCTURE
00039 
00040   SEL_ARG objects are linked together in a graph. The meaning of the graph
00041   is better demostrated by an example:
00042 
00043      tree->keys[i]
00044       |
00045       |             $              $
00046       |    part=1   $     part=2   $    part=3
00047       |             $              $
00048       |  +-------+  $   +-------+  $   +--------+
00049       |  | kp1<1 |--$-->| kp2=5 |--$-->| kp3=10 |
00050       |  +-------+  $   +-------+  $   +--------+
00051       |      |      $              $       |
00052       |      |      $              $   +--------+
00053       |      |      $              $   | kp3=12 |
00054       |      |      $              $   +--------+
00055       |  +-------+  $              $
00056       \->| kp1=2 |--$--------------$-+
00057          +-------+  $              $ |   +--------+
00058              |      $              $  ==>| kp3=11 |
00059          +-------+  $              $ |   +--------+
00060          | kp1=3 |--$--------------$-+       |
00061          +-------+  $              $     +--------+
00062              |      $              $     | kp3=14 |
00063             ...     $              $     +--------+
00064 
00065   The entire graph is partitioned into "interval lists".
00066 
00067   An interval list is a sequence of ordered disjoint intervals over the same
00068   key part. SEL_ARG are linked via "next" and "prev" pointers. Additionally,
00069   all intervals in the list form an RB-tree, linked via left/right/parent
00070   pointers. The RB-tree root SEL_ARG object will be further called "root of the
00071   interval list".
00072 
00073     In the example pic, there are 4 interval lists:
00074     "kp<1 OR kp1=2 OR kp1=3", "kp2=5", "kp3=10 OR kp3=12", "kp3=11 OR kp3=13".
00075     The vertical lines represent SEL_ARG::next/prev pointers.
00076 
00077   In an interval list, each member X may have SEL_ARG::next_key_part pointer
00078   pointing to the root of another interval list Y. The pointed interval list
00079   must cover a key part with greater number (i.e. Y->part > X->part).
00080 
00081     In the example pic, the next_key_part pointers are represented by
00082     horisontal lines.
00083 
00084   2. SEL_ARG GRAPH SEMANTICS
00085 
00086   It represents a condition in a special form (we don't have a name for it ATM)
00087   The SEL_ARG::next/prev is "OR", and next_key_part is "AND".
00088 
00089   For example, the picture represents the condition in form:
00090    (kp1 < 1 AND kp2=5 AND (kp3=10 OR kp3=12)) OR
00091    (kp1=2 AND (kp3=11 OR kp3=14)) OR
00092    (kp1=3 AND (kp3=11 OR kp3=14))
00093 
00094 
00095   3. SEL_ARG GRAPH USE
00096 
00097   Use get_mm_tree() to construct SEL_ARG graph from WHERE condition.
00098   Then walk the SEL_ARG graph and get a list of dijsoint ordered key
00099   intervals (i.e. intervals in form
00100 
00101    (constA1, .., const1_K) < (keypart1,.., keypartK) < (constB1, .., constB_K)
00102 
00103   Those intervals can be used to access the index. The uses are in:
00104    - check_quick_select() - Walk the SEL_ARG graph and find an estimate of
00105                             how many table records are contained within all
00106                             intervals.
00107    - get_quick_select()   - Walk the SEL_ARG, materialize the key intervals,
00108                             and create QuickRangeSelect object that will
00109                             read records within these intervals.
00110 
00111   4. SPACE COMPLEXITY NOTES
00112 
00113     SEL_ARG graph is a representation of an ordered disjoint sequence of
00114     intervals over the ordered set of index tuple values.
00115 
00116     For multi-part keys, one can construct a WHERE expression such that its
00117     list of intervals will be of combinatorial size. Here is an example:
00118 
00119       (keypart1 IN (1,2, ..., n1)) AND
00120       (keypart2 IN (1,2, ..., n2)) AND
00121       (keypart3 IN (1,2, ..., n3))
00122 
00123     For this WHERE clause the list of intervals will have n1*n2*n3 intervals
00124     of form
00125 
00126       (keypart1, keypart2, keypart3) = (k1, k2, k3), where 1 <= k{i} <= n{i}
00127 
00128     SEL_ARG graph structure aims to reduce the amount of required space by
00129     "sharing" the elementary intervals when possible (the pic at the
00130     beginning of this comment has examples of such sharing). The sharing may
00131     prevent combinatorial blowup:
00132 
00133       There are WHERE clauses that have combinatorial-size interval lists but
00134       will be represented by a compact SEL_ARG graph.
00135       Example:
00136         (keypartN IN (1,2, ..., n1)) AND
00137         ...
00138         (keypart2 IN (1,2, ..., n2)) AND
00139         (keypart1 IN (1,2, ..., n3))
00140 
00141     but not in all cases:
00142 
00143     - There are WHERE clauses that do have a compact SEL_ARG-graph
00144       representation but get_mm_tree() and its callees will construct a
00145       graph of combinatorial size.
00146       Example:
00147         (keypart1 IN (1,2, ..., n1)) AND
00148         (keypart2 IN (1,2, ..., n2)) AND
00149         ...
00150         (keypartN IN (1,2, ..., n3))
00151 
00152     - There are WHERE clauses for which the minimal possible SEL_ARG graph
00153       representation will have combinatorial size.
00154       Example:
00155         By induction: Let's take any interval on some keypart in the middle:
00156 
00157            kp15=c0
00158 
00159         Then let's AND it with this interval 'structure' from preceding and
00160         following keyparts:
00161 
00162           (kp14=c1 AND kp16=c3) OR keypart14=c2) (*)
00163 
00164         We will obtain this SEL_ARG graph:
00165 
00166              kp14     $      kp15      $      kp16
00167                       $                $
00168          +---------+  $   +---------+  $   +---------+
00169          | kp14=c1 |--$-->| kp15=c0 |--$-->| kp16=c3 |
00170          +---------+  $   +---------+  $   +---------+
00171               |       $                $
00172          +---------+  $   +---------+  $
00173          | kp14=c2 |--$-->| kp15=c0 |  $
00174          +---------+  $   +---------+  $
00175                       $                $
00176 
00177        Note that we had to duplicate "kp15=c0" and there was no way to avoid
00178        that.
00179        The induction step: AND the obtained expression with another "wrapping"
00180        expression like (*).
00181        When the process ends because of the limit on max. number of keyparts
00182        we'll have:
00183 
00184          WHERE clause length  is O(3*#max_keyparts)
00185          SEL_ARG graph size   is O(2^(#max_keyparts/2))
00186 
00187        (it is also possible to construct a case where instead of 2 in 2^n we
00188         have a bigger constant, e.g. 4, and get a graph with 4^(31/2)= 2^31
00189         nodes)
00190 
00191     We avoid consuming too much memory by setting a limit on the number of
00192     SEL_ARG object we can construct during one range analysis invocation.
00193 */
00194 
00195 class SEL_ARG :public memory::SqlAlloc
00196 {
00197 public:
00198   uint8_t min_flag,max_flag,maybe_flag;
00199   uint8_t part;         // Which key part
00200   uint8_t maybe_null;
00201   /*
00202     Number of children of this element in the RB-tree, plus 1 for this
00203     element itself.
00204   */
00205   uint16_t elements;
00206   /*
00207     Valid only for elements which are RB-tree roots: Number of times this
00208     RB-tree is referred to (it is referred by SEL_ARG::next_key_part or by
00209     SEL_TREE::keys[i] or by a temporary SEL_ARG* variable)
00210   */
00211   ulong use_count;
00212 
00213   Field *field;
00214   unsigned char *min_value,*max_value;      // Pointer to range
00215 
00216   /*
00217     eq_tree() requires that left == right == 0 if the type is MAYBE_KEY.
00218    */
00219   SEL_ARG *left,*right;   /* R-B tree children */
00220   SEL_ARG *next,*prev;    /* Links for bi-directional interval list */
00221   SEL_ARG *parent;        /* R-B tree parent */
00222   SEL_ARG *next_key_part;
00223   enum leaf_color { BLACK,RED } color;
00224   enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type;
00225 
00226   enum 
00227   { 
00228     MAX_SEL_ARGS = 16000 
00229   };
00230 
00231   SEL_ARG() {}
00232 
00233   SEL_ARG(SEL_ARG &);
00234 
00235   SEL_ARG(Field *,const unsigned char *, const unsigned char *);
00236 
00237   SEL_ARG(Field *field, 
00238           uint8_t part, 
00239           unsigned char *min_value, 
00240           unsigned char *max_value,
00241           uint8_t min_flag, 
00242           uint8_t max_flag, 
00243           uint8_t maybe_flag);
00244 
00245   SEL_ARG(enum Type type_arg)
00246     :
00247       min_flag(0),
00248       elements(1),
00249       use_count(1),
00250       left(0),
00251       right(0),
00252       next_key_part(0),
00253       color(BLACK), 
00254       type(type_arg)
00255   {}
00256 
00257   int size() const
00258   {
00259     return elements;
00260   }
00261 
00262   inline bool is_same(SEL_ARG *arg)
00263   {
00264     if (type != arg->type || part != arg->part)
00265       return 0;
00266     if (type != KEY_RANGE)
00267       return 1;
00268     return (cmp_min_to_min(arg) == 0 && cmp_max_to_max(arg) == 0);
00269   }
00270 
00271   inline void merge_flags(SEL_ARG *arg) 
00272   { 
00273     maybe_flag|= arg->maybe_flag; 
00274   }
00275 
00276   inline void maybe_smaller() 
00277   { 
00278     maybe_flag= 1; 
00279   }
00280 
00281   /* Return true iff it's a single-point null interval */
00282   inline bool is_null_interval() 
00283   { 
00284     return (maybe_null && max_value[0] == 1);
00285   }
00286 
00287   inline int cmp_min_to_min(SEL_ARG *arg)
00288   {
00289     return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag);
00290   }
00291 
00292   inline int cmp_min_to_max(SEL_ARG *arg)
00293   {
00294     return sel_cmp(field,min_value, arg->max_value, min_flag, arg->max_flag);
00295   }
00296 
00297   inline int cmp_max_to_max(SEL_ARG *arg)
00298   {
00299     return sel_cmp(field,max_value, arg->max_value, max_flag, arg->max_flag);
00300   }
00301 
00302   inline int cmp_max_to_min(SEL_ARG *arg)
00303   {
00304     return sel_cmp(field,max_value, arg->min_value, max_flag, arg->min_flag);
00305   }
00306 
00307   SEL_ARG *clone_and(SEL_ARG *arg);
00308 
00309   SEL_ARG *clone_first(SEL_ARG *arg);
00310 
00311   SEL_ARG *clone_last(SEL_ARG *arg);
00312 
00313   SEL_ARG *clone(RangeParameter *param, SEL_ARG *new_parent, SEL_ARG **next);
00314 
00315   bool copy_min(SEL_ARG *arg);
00316 
00317   bool copy_max(SEL_ARG *arg);
00318 
00319   void copy_min_to_min(SEL_ARG *arg);
00320 
00321   void copy_min_to_max(SEL_ARG *arg);
00322 
00323   void copy_max_to_min(SEL_ARG *arg);
00324 
00325   /* returns a number of keypart values (0 or 1) appended to the key buffer */
00326   int store_min(uint32_t length, unsigned char **min_key, uint32_t min_key_flag);
00327 
00328   /* returns a number of keypart values (0 or 1) appended to the key buffer */
00329   int store_max(uint32_t length, unsigned char **max_key, uint32_t max_key_flag);
00330 
00331   /* returns a number of keypart values appended to the key buffer */
00332   int store_min_key(KEY_PART *key, unsigned char **range_key, uint32_t *range_key_flag);
00333 
00334   /* returns a number of keypart values appended to the key buffer */
00335   int store_max_key(KEY_PART *key, unsigned char **range_key, uint32_t *range_key_flag);
00336 
00337   SEL_ARG *insert(SEL_ARG *key);
00338   SEL_ARG *tree_delete(SEL_ARG *key);
00339   SEL_ARG *find_range(SEL_ARG *key);
00340   SEL_ARG *rb_insert(SEL_ARG *leaf);
00341 
00342   friend SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key, SEL_ARG *par);
00343 
00344   SEL_ARG *first();
00345 
00346   SEL_ARG *last();
00347 
00348   void make_root();
00349 
00350   inline bool simple_key()
00351   {
00352     return (! next_key_part && elements == 1);
00353   }
00354 
00355   void increment_use_count(long count)
00356   {
00357     if (next_key_part)
00358     {
00359       next_key_part->use_count+= count;
00360       count*= (next_key_part->use_count - count);
00361       for (SEL_ARG *pos= next_key_part->first(); pos; pos= pos->next)
00362         if (pos->next_key_part)
00363           pos->increment_use_count(count);
00364     }
00365   }
00366 
00367   void free_tree()
00368   {
00369     for (SEL_ARG *pos= first(); pos; pos= pos->next)
00370       if (pos->next_key_part)
00371       {
00372         pos->next_key_part->use_count--;
00373         pos->next_key_part->free_tree();
00374       }
00375   }
00376 
00377   inline SEL_ARG **parent_ptr()
00378   {
00379     return parent->left == this ? &parent->left : &parent->right;
00380   }
00381 
00382 
00383   /*
00384     Check if this SEL_ARG object represents a single-point interval
00385 
00386     SYNOPSIS
00387       is_singlepoint()
00388 
00389     DESCRIPTION
00390       Check if this SEL_ARG object (not tree) represents a single-point
00391       interval, i.e. if it represents a "keypart = const" or
00392       "keypart IS NULL".
00393 
00394     RETURN
00395       true   This SEL_ARG object represents a singlepoint interval
00396       false  Otherwise
00397   */
00398 
00399   bool is_singlepoint()
00400   {
00401     /*
00402       Check for NEAR_MIN ("strictly less") and NO_MIN_RANGE (-inf < field)
00403       flags, and the same for right edge.
00404     */
00405     if (min_flag || max_flag)
00406       return false;
00407     unsigned char *min_val= min_value;
00408     unsigned char *max_val= max_value;
00409 
00410     if (maybe_null)
00411     {
00412       /* First byte is a NULL value indicator */
00413       if (*min_val != *max_val)
00414         return false;
00415 
00416       if (*min_val)
00417         return true; /* This "x IS NULL" */
00418       min_val++;
00419       max_val++;
00420     }
00421     return ! field->key_cmp(min_val, max_val);
00422   }
00423 
00424   SEL_ARG *clone_tree(RangeParameter *param);
00425 
00426 private:
00427 
00428   /*
00429      Check if a compare is ok, when one takes ranges in account
00430      Returns -2 or 2 if the ranges where 'joined' like  < 2 and >= 2
00431    */
00432   int sel_cmp(Field *in_field, 
00433               unsigned char *a, 
00434               unsigned char *b, 
00435               uint8_t a_flag,
00436               uint8_t b_flag)
00437   {
00438     int cmp= 0;
00439     /* First check if there was a compare to a min or max element */
00440     if (a_flag & (NO_MIN_RANGE | NO_MAX_RANGE))
00441     {
00442       if ((a_flag & (NO_MIN_RANGE | NO_MAX_RANGE)) ==
00443           (b_flag & (NO_MIN_RANGE | NO_MAX_RANGE)))
00444         return 0;
00445       return (a_flag & NO_MIN_RANGE) ? -1 : 1;
00446     }
00447     if (b_flag & (NO_MIN_RANGE | NO_MAX_RANGE))
00448       return (b_flag & NO_MIN_RANGE) ? 1 : -1;
00449 
00450     if (in_field->real_maybe_null())      // If null is part of key
00451     {
00452       if (*a != *b)
00453       {
00454         return *a ? -1 : 1;
00455       }
00456       if (*a)
00457         goto end;         // NULL where equal
00458       a++; b++;         // Skip NULL marker
00459     }
00460     cmp= in_field->key_cmp(a , b);
00461     if (cmp) return cmp < 0 ? -1 : 1;   // The values differed
00462 
00463     // Check if the compared equal arguments was defined with open/closed range
00464 end:
00465     if (a_flag & (NEAR_MIN | NEAR_MAX))
00466     {
00467       if ((a_flag & (NEAR_MIN | NEAR_MAX)) == (b_flag & (NEAR_MIN | NEAR_MAX)))
00468         return 0;
00469       if (! (b_flag & (NEAR_MIN | NEAR_MAX)))
00470         return (a_flag & NEAR_MIN) ? 2 : -2;
00471       return (a_flag & NEAR_MIN) ? 1 : -1;
00472     }
00473     if (b_flag & (NEAR_MIN | NEAR_MAX))
00474       return (b_flag & NEAR_MIN) ? -2 : 2;
00475     return 0;         // The elements where equal
00476   }
00477 
00478   
00479 };
00480 
00481 SEL_ARG *rb_delete_fixup(SEL_ARG *root,
00482                          SEL_ARG *key,
00483                          SEL_ARG *par);
00484 
00485 extern SEL_ARG null_element;
00486 
00487 } /* namespace optimizer */
00488 
00489 } /* namespace drizzled */
00490