Commit 6ba2ca2b authored by unknown's avatar unknown
Browse files

Merge joreland@bk-internal.mysql.com:/home/bk/mysql-4.1-ndb

into mysql.com:/home/jonas/src/mysql-4.1-ndb

parents 1a971260 28de5d36
Loading
Loading
Loading
Loading
+133 −0
Original line number Diff line number Diff line
#
# test range scan bounds
# output to mysql-test/t/ndb_range_bounds.test
#
# give option --all to generate all cases
#

use strict;
use integer;

my $all = shift;
!defined($all) || ($all eq '--all' && !defined(shift))
  or die "only available option is --all";

my $table = 't';

print <<EOF;
--source include/have_ndb.inc

--disable_warnings
drop table if exists $table;
--enable_warnings

# test range scan bounds
# generated by mysql-test/ndb/ndb_range_bounds.pl
# all selects must return 0

EOF

sub cut ($$@) {
  my($op, $key, @v) = @_;
  $op = '==' if $op eq '=';
  my(@w);
  eval "\@w = grep(\$_ $op $key, \@v)";
  $@ and die $@;
  return @w;
}

sub mkdummy (\@) {
  my ($val) = @_;
  return {
    'dummy' => 1,
    'exp' => '9 = 9',
    'cnt' => scalar @$val,
  };
}

sub mkone ($$$\@) {
  my($col, $op, $key, $val) = @_;
  my $cnt = scalar cut($op, $key, @$val);
  return {
    'exp' => "$col $op $key",
    'cnt' => $cnt,
  };
}

sub mktwo ($$$$$\@) {
  my($col, $op1, $key1, $op2, $key2, $val) = @_;
  my $cnt = scalar cut($op2, $key2, cut($op1, $key1, @$val));
  return {
    'exp' => "$col $op1 $key1 and $col $op2 $key2",
    'cnt' => $cnt,
  };
}

sub mkall ($$$\@) {
  my($col, $key1, $key2, $val) = @_;
  my @a = ();
  my $p = mkdummy(@$val);
  push(@a, $p) if $all;
  my @ops1 = $all ? qw(< <= = >= >) : qw(= >= >);
  my @ops2 = $all ? qw(< <= = >= >) : qw(< <=);
  for my $op1 (@ops1) {
    my $p = mkone($col, $op1, $key1, @$val);
    push(@a, $p) if $all || $p->{cnt} != 0;
    for my $op2 (@ops2) {
      my $p = mktwo($col, $op1, $key1, $op2, $key2, @$val);
      push(@a, $p) if $all || $p->{cnt} != 0;
    }
  }
  return \@a;
}

for my $nn ("bcd", "") {
  my %nn;
  for my $x (qw(b c d)) {
    $nn{$x} = $nn =~ /$x/ ? "not null" : "null";
  }
  print <<EOF;
create table $table (
  a int primary key,
  b int $nn{b},
  c int $nn{c},
  d int $nn{d},
  index (b, c, d)
) engine=ndb;
EOF
  my @val = (0..4);
  my $v0 = 0;
  for my $v1 (@val) {
    for my $v2 (@val) {
      for my $v3 (@val) {
	print "insert into $table values($v0, $v1, $v2, $v3);\n";
	$v0++;
      }
    }
  }
  my $key1 = 1;
  my $key2 = 3;
  my $a1 = mkall('b', $key1, $key2, @val);
  my $a2 = mkall('c', $key1, $key2, @val);
  my $a3 = mkall('d', $key1, $key2, @val);
  for my $p1 (@$a1) {
    my $cnt1 = $p1->{cnt} * @val * @val;
    print "select count(*) - $cnt1 from $table";
    print " where $p1->{exp};\n";
    for my $p2 (@$a2) {
      my $cnt2 = $p1->{cnt} * $p2->{cnt} * @val;
      print "select count(*) - $cnt2 from $table";
      print " where $p1->{exp} and $p2->{exp};\n";
      for my $p3 (@$a3) {
	my $cnt3 = $p1->{cnt} * $p2->{cnt} * $p3->{cnt};
	print "select count(*) - $cnt3 from $table";
	print " where $p1->{exp} and $p2->{exp} and $p3->{exp};\n";
      }
    }
  }
  print <<EOF;
drop table $table;
EOF
}

# vim: set sw=2:
+0 −1
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ private:
  Uint32 tuxScanPtrI;
  /*
   * Number of words of bound info included after fixed signal data.
   * Starts with 5 unused words (word 0 is length used by LQH).
   */
  Uint32 boundAiLength;
};
+18 −28
Original line number Diff line number Diff line
@@ -55,28 +55,12 @@ public:
    return readTuples(LM_Exclusive, 0, parallell, false);
  }

  /**
   * @name Define Range Scan
   *
   * A range scan is a scan on an ordered index.  The operation is on
   * the index table but tuples are returned from the primary table.
   * The index contains all tuples where at least one index key has not
   * null value.
   *
   * A range scan is currently opened via a normal open scan method.
   * Bounds can be defined for each index key.  After setting bounds,
   * usual scan methods can be used (get value, interpreter, take over).
   * These operate on the primary table.
   *
   * @{
   */

  /**
   * Type of ordered index key bound.  The values (0-4) will not change
   * and can be used explicitly (e.g. they could be computed).
   */
  enum BoundType {
    BoundLE = 0,        ///< lower bound,
    BoundLE = 0,        ///< lower bound
    BoundLT = 1,        ///< lower bound, strict
    BoundGE = 2,        ///< upper bound
    BoundGT = 3,        ///< upper bound, strict
@@ -86,20 +70,28 @@ public:
  /**
   * Define bound on index key in range scan.
   *
   * Each index key can have lower and/or upper bound, or can be set
   * equal to a value.  The bounds can be defined in any order but
   * a duplicate definition is an error.
   * Each index key can have lower and/or upper bound.  Setting the key
   * equal to a value defines both upper and lower bounds.  The bounds
   * can be defined in any order.  Conflicting definitions is an error.
   *
   * For equality, it is better to use BoundEQ instead of the equivalent
   * pair of BoundLE and BoundGE.  This is especially true when table
   * distribution key is an initial part of the index key.
   *
   * The bounds must specify a single range i.e. they are on an initial
   * sequence of index keys and the condition is equality for all but
   * (at most) the last key which has a lower and/or upper bound.
   * The sets of lower and upper bounds must be on initial sequences of
   * index keys.  All but possibly the last bound must be non-strict.
   * So "a >= 2 and b > 3" is ok but "a > 2 and b >= 3" is not.
   *
   * The scan may currently return tuples for which the bounds are not
   * satisfied.  For example, "a <= 2 and b <= 3" scans the index up to
   * (a=2, b=3) but also returns any (a=1, b=4).
   *
   * NULL is treated like a normal value which is less than any not-NULL
   * value and equal to another NULL value.  To search for NULL use
   * value and equal to another NULL value.  To compare against NULL use
   * setBound with null pointer (0).
   *
   * An index stores also all-NULL keys (this may become optional).
   * Doing index scan with empty bound set returns all table tuples.
   * An index stores also all-NULL keys.  Doing index scan with empty
   * bound set returns all table tuples.
   *
   * @param attrName    Attribute name, alternatively:
   * @param anAttrId    Index column id (starting from 0)
@@ -117,8 +109,6 @@ public:
   */
  int setBound(Uint32 anAttrId, int type, const void* aValue, Uint32 len = 0);

  /** @} *********************************************************************/

  /**
   * Reset bounds and put operation in list that will be
   *   sent on next execute
+0 −1
Original line number Diff line number Diff line
@@ -7692,7 +7692,6 @@ void Dblqh::accScanConfScanLab(Signal* signal)
  Uint32 boundAiLength = tcConnectptr.p->primKeyLen - 4;
  if (scanptr.p->rangeScan) {
    jam();
    // bound info length is in first of the 5 header words
    TuxBoundInfo* const req = (TuxBoundInfo*)signal->getDataPtrSend();
    req->errorCode = RNIL;
    req->tuxScanPtrI = scanptr.p->scanAccPtr;
+56 −27
Original line number Diff line number Diff line
@@ -172,12 +172,21 @@ private:
   * Physical tuple address in TUP.  Provides fast access to table tuple
   * or index node.  Valid within the db node and across timeslices.
   * Not valid between db nodes or across restarts.
   *
   * To avoid wasting an Uint16 the pageid is split in two.
   */
  struct TupLoc {
    Uint32 m_pageId;            // page i-value
  private:
    Uint16 m_pageId1;           // page i-value (big-endian)
    Uint16 m_pageId2;
    Uint16 m_pageOffset;        // page offset in words
  public:
    TupLoc();
    TupLoc(Uint32 pageId, Uint16 pageOffset);
    Uint32 getPageId() const;
    void setPageId(Uint32 pageId);
    Uint32 getPageOffset() const;
    void setPageOffset(Uint32 pageOffset);
    bool operator==(const TupLoc& loc) const;
    bool operator!=(const TupLoc& loc) const;
  };
@@ -224,18 +233,13 @@ private:
   * work entry                 part 5
   *
   * There are 3 links to other nodes: left child, right child, parent.
   * These are in TupLoc format but the pageIds and pageOffsets are
   * stored in separate arrays (saves 1 word).
   *
   * Occupancy (number of entries) is at least 1 except temporarily when
   * a node is about to be removed.  If occupancy is 1, only max entry
   * is present but both min and max prefixes are set.
   * a node is about to be removed.
   */
  struct TreeNode;
  friend struct TreeNode;
  struct TreeNode {
    Uint32 m_linkPI[3];         // link to 0-left child 1-right child 2-parent
    Uint16 m_linkPO[3];         // page offsets for above real page ids
    TupLoc m_link[3];           // link to 0-left child 1-right child 2-parent
    unsigned m_side : 2;        // we are 0-left child 1-right child 2-root
    int m_balance : 2;          // balance -1, 0, +1
    unsigned pad1 : 4;
@@ -805,22 +809,52 @@ Dbtux::ConstData::operator=(Data data)

inline
Dbtux::TupLoc::TupLoc() :
  m_pageId(RNIL),
  m_pageId1(RNIL >> 16),
  m_pageId2(RNIL & 0xFFFF),
  m_pageOffset(0)
{
}

inline
Dbtux::TupLoc::TupLoc(Uint32 pageId, Uint16 pageOffset) :
  m_pageId(pageId),
  m_pageId1(pageId >> 16),
  m_pageId2(pageId & 0xFFFF),
  m_pageOffset(pageOffset)
{
}

inline Uint32
Dbtux::TupLoc::getPageId() const
{
  return (m_pageId1 << 16) | m_pageId2;
}

inline void
Dbtux::TupLoc::setPageId(Uint32 pageId)
{
  m_pageId1 = (pageId >> 16);
  m_pageId2 = (pageId & 0xFFFF);
}

inline Uint32
Dbtux::TupLoc::getPageOffset() const
{
  return (Uint32)m_pageOffset;
}

inline void
Dbtux::TupLoc::setPageOffset(Uint32 pageOffset)
{
  m_pageOffset = (Uint16)pageOffset;
}

inline bool
Dbtux::TupLoc::operator==(const TupLoc& loc) const
{
  return m_pageId == loc.m_pageId && m_pageOffset == loc.m_pageOffset;
  return
    m_pageId1 == loc.m_pageId1 &&
    m_pageId2 == loc.m_pageId2 &&
    m_pageOffset == loc.m_pageOffset;
}

inline bool
@@ -851,13 +885,13 @@ Dbtux::TreeEnt::eq(const TreeEnt ent) const
inline int
Dbtux::TreeEnt::cmp(const TreeEnt ent) const
{
  if (m_tupLoc.m_pageId < ent.m_tupLoc.m_pageId)
  if (m_tupLoc.getPageId() < ent.m_tupLoc.getPageId())
    return -1;
  if (m_tupLoc.m_pageId > ent.m_tupLoc.m_pageId)
  if (m_tupLoc.getPageId() > ent.m_tupLoc.getPageId())
    return +1;
  if (m_tupLoc.m_pageOffset < ent.m_tupLoc.m_pageOffset)
  if (m_tupLoc.getPageOffset() < ent.m_tupLoc.getPageOffset())
    return -1;
  if (m_tupLoc.m_pageOffset > ent.m_tupLoc.m_pageOffset)
  if (m_tupLoc.getPageOffset() > ent.m_tupLoc.getPageOffset())
    return +1;
  if (m_tupVersion < ent.m_tupVersion)
    return -1;
@@ -880,12 +914,9 @@ Dbtux::TreeNode::TreeNode() :
  m_occup(0),
  m_nodeScan(RNIL)
{
  m_linkPI[0] = NullTupLoc.m_pageId;
  m_linkPO[0] = NullTupLoc.m_pageOffset;
  m_linkPI[1] = NullTupLoc.m_pageId;
  m_linkPO[1] = NullTupLoc.m_pageOffset;
  m_linkPI[2] = NullTupLoc.m_pageId;
  m_linkPO[2] = NullTupLoc.m_pageOffset;
  m_link[0] = NullTupLoc;
  m_link[1] = NullTupLoc;
  m_link[2] = NullTupLoc;
}

// Dbtux::TreeHead
@@ -913,7 +944,6 @@ Dbtux::TreeHead::getSize(AccSize acc) const
  case AccFull:
    return m_nodeSize;
  }
  abort();
  return 0;
}

@@ -1088,13 +1118,13 @@ inline Dbtux::TupLoc
Dbtux::NodeHandle::getLink(unsigned i)
{
  ndbrequire(i <= 2);
  return TupLoc(m_node->m_linkPI[i], m_node->m_linkPO[i]);
  return m_node->m_link[i];
}

inline unsigned
Dbtux::NodeHandle::getChilds()
{
  return (getLink(0) != NullTupLoc) + (getLink(1) != NullTupLoc);
  return (m_node->m_link[0] != NullTupLoc) + (m_node->m_link[1] != NullTupLoc);
}

inline unsigned
@@ -1125,8 +1155,7 @@ inline void
Dbtux::NodeHandle::setLink(unsigned i, TupLoc loc)
{
  ndbrequire(i <= 2);
  m_node->m_linkPI[i] = loc.m_pageId;
  m_node->m_linkPO[i] = loc.m_pageOffset;
  m_node->m_link[i] = loc;
}

inline void
@@ -1224,7 +1253,7 @@ Dbtux::getTupAddr(const Frag& frag, TreeEnt ent)
  const Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit];
  const TupLoc tupLoc = ent.m_tupLoc;
  Uint32 tupAddr = NullTupAddr;
  c_tup->tuxGetTupAddr(tableFragPtrI, tupLoc.m_pageId, tupLoc.m_pageOffset, tupAddr);
  c_tup->tuxGetTupAddr(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), tupAddr);
  jamEntry();
  return tupAddr;
}
Loading