Example #1
0
 @Override
 public Cursor find(Session session, SearchRow first, SearchRow last) {
   long min, max;
   if (first == null || mainIndexColumn < 0) {
     min = Long.MIN_VALUE;
   } else {
     Value v = first.getValue(mainIndexColumn);
     if (v == null) {
       min = 0;
     } else {
       min = v.getLong();
     }
   }
   if (last == null || mainIndexColumn < 0) {
     max = Long.MAX_VALUE;
   } else {
     Value v = last.getValue(mainIndexColumn);
     if (v == null) {
       max = Long.MAX_VALUE;
     } else {
       max = v.getLong();
     }
   }
   TransactionMap<Value, Value> map = getMap(session);
   return new MVStoreCursor(session, map.keyIterator(ValueLong.get(min)), max);
 }
Example #2
0
 /**
  * Get the key from the row.
  *
  * @param row the row
  * @param ifEmpty the value to use if the row is empty
  * @param ifNull the value to use if the column is NULL
  * @return the key
  */
 long getKey(SearchRow row, long ifEmpty, long ifNull) {
   if (row == null) {
     return ifEmpty;
   }
   Value v = row.getValue(mainIndexColumn);
   if (v == null) {
     throw DbException.throwInternalError(row.toString());
   } else if (v == ValueNull.INSTANCE) {
     return ifNull;
   }
   return v.getLong();
 }
Example #3
0
 /**
  * Compare the positions of two rows.
  *
  * @param rowData the first row
  * @param compare the second row
  * @return 0 if both rows are equal, -1 if the first row is smaller, otherwise 1
  */
 int compareKeys(SearchRow rowData, SearchRow compare) {
   long k1 = rowData.getKey();
   long k2 = compare.getKey();
   if (k1 == k2) {
     if (isMultiVersion) {
       int v1 = rowData.getVersion();
       int v2 = compare.getVersion();
       return MathUtils.compareInt(v2, v1);
     }
     return 0;
   }
   return k1 > k2 ? 1 : -1;
 }
Example #4
0
  /**
   * Check if one of the columns is NULL and multiple rows with NULL are allowed using the current
   * compatibility mode for unique indexes. Note: NULL behavior is complicated in SQL.
   *
   * @param newRow the row to check
   * @return true if one of the columns is null and multiple nulls in unique indexes are allowed
   */
  protected boolean containsNullAndAllowMultipleNull(SearchRow newRow) {
    Mode mode = database.getMode();
    // 1. 对于唯一索引,必须完全唯一,适用于Derby/HSQLDB/MSSQLServer
    if (mode.uniqueIndexSingleNull) {
      // 不允许出现:
      // (x, null)
      // (x, null)
      // 也不允许出现:
      // (null, null)
      // (null, null)
      return false;
    } else if (mode.uniqueIndexSingleNullExceptAllColumnsAreNull) {
      // 2. 对于唯一索引,索引记录可以全为null,适用于Oracle

      // 不允许出现:
      // (x, null)
      // (x, null)
      // 但是允许出现:
      // (null, null)
      // (null, null)
      for (int index : columnIds) {
        Value v = newRow.getValue(index);
        if (v != ValueNull.INSTANCE) {
          return false;
        }
      }
      return true;
    }
    // 3. 对于唯一索引,只要一个为null,就是合法的,适用于REGULAR(即H2)/DB2/MySQL/PostgreSQL

    // 即允许出现:
    // (x, null)
    // (x, null)
    // 也允许出现:
    // (null, null)
    // (null, null)

    // 也就是说,只要相同的两条索引记录包含null即可
    for (int index : columnIds) {
      Value v = newRow.getValue(index);
      if (v == ValueNull.INSTANCE) {
        return true;
      }
    }

    // 4. 对于唯一索引,没有null时是不允许出现两条相同的索引记录的
    return false;
  }
Example #5
0
  /** {@inheritDoc} */
  @Override
  public int compareRows(SearchRow rowData, SearchRow compare) {
    if (rowData == compare) return 0;

    for (int i = 0, len = indexColumns.length; i < len; i++) {
      int index = columnIds[i];

      Value v1 = rowData.getValue(index);
      Value v2 = compare.getValue(index);

      if (v1 == null || v2 == null) return 0;

      int c = compareValues(v1, v2, indexColumns[i].sortType);

      if (c != 0) return c;
    }
    return 0;
  }
Example #6
0
 @Override
 public int compareRows(SearchRow rowData, SearchRow compare) { // 只比较索引字段,并不一定是所有字段
   if (rowData == compare) {
     return 0;
   }
   for (int i = 0, len = indexColumns.length; i < len; i++) {
     int index = columnIds[i];
     Value v = compare.getValue(index);
     if (v == null) { // 只要compare中有null值就认为无法比较,直接认为rowData和compare相等(通常在查询时在where中再比较)
       // can't compare further
       return 0;
     }
     int c = compareValues(rowData.getValue(index), v, indexColumns[i].sortType);
     if (c != 0) {
       return c;
     }
   }
   return 0;
 }
Example #7
0
 @Override
 public Cursor findFirstOrLast(Session session, boolean first) {
   if (closed) {
     throw DbException.throwInternalError();
   }
   if (first) {
     // TODO optimization: this loops through NULL
     Cursor cursor = find(session, null, null);
     while (cursor.next()) {
       SearchRow row = cursor.getSearchRow();
       Value v = row.getValue(columnIds[0]);
       if (v != ValueNull.INSTANCE) {
         return cursor;
       }
     }
     return cursor;
   }
   TreeNode x = root, n;
   while (x != null) {
     n = x.right;
     if (n == null) {
       break;
     }
     x = n;
   }
   TreeCursor cursor = new TreeCursor(this, x, null, null);
   if (x == null) {
     return cursor;
   }
   // TODO optimization: this loops through NULL elements
   do {
     SearchRow row = cursor.getSearchRow();
     if (row == null) {
       break;
     }
     Value v = row.getValue(columnIds[0]);
     if (v != ValueNull.INSTANCE) {
       return cursor;
     }
   } while (cursor.previous());
   return cursor;
 }
Example #8
0
 @Override
 public Cursor find(Session session, SearchRow first, SearchRow last) {
   ValueLong min, max;
   if (first == null) {
     min = MIN;
   } else if (mainIndexColumn < 0) {
     min = ValueLong.get(first.getKey());
   } else {
     ValueLong v = (ValueLong) first.getValue(mainIndexColumn);
     if (v == null) {
       min = ValueLong.get(first.getKey());
     } else {
       min = v;
     }
   }
   if (last == null) {
     max = MAX;
   } else if (mainIndexColumn < 0) {
     max = ValueLong.get(last.getKey());
   } else {
     ValueLong v = (ValueLong) last.getValue(mainIndexColumn);
     if (v == null) {
       max = ValueLong.get(last.getKey());
     } else {
       max = v;
     }
   }
   TransactionMap<Value, Value> map = getMap(session);
   return new MVStoreCursor(session, map.entryIterator(min), max);
 }
Example #9
0
 private void queryDistinct(ResultTarget result, long limitRows) {
   // limitRows must be long, otherwise we get an int overflow
   // if limitRows is at or near Integer.MAX_VALUE
   // limitRows is never 0 here
   if (limitRows > 0 && offsetExpr != null) {
     int offset = offsetExpr.getValue(session).getInt();
     if (offset > 0) {
       limitRows += offset;
     }
   }
   int rowNumber = 0;
   setCurrentRowNumber(0);
   Index index = topTableFilter.getIndex();
   SearchRow first = null;
   int columnIndex = index.getColumns()[0].getColumnId();
   while (true) {
     setCurrentRowNumber(rowNumber + 1);
     Cursor cursor = index.findNext(session, first, null);
     if (!cursor.next()) {
       break;
     }
     SearchRow found = cursor.getSearchRow();
     Value value = found.getValue(columnIndex);
     if (first == null) {
       first = topTableFilter.getTable().getTemplateSimpleRow(true);
     }
     first.setValue(columnIndex, value);
     Value[] row = {value};
     result.addRow(row);
     rowNumber++;
     if ((sort == null || sortUsingIndex) && limitRows > 0 && rowNumber >= limitRows) {
       break;
     }
     if (sampleSize > 0 && rowNumber >= sampleSize) {
       break;
     }
   }
 }
 @Override
 public boolean next() {
   synchronized (sync) {
     if (SysProperties.CHECK && end) {
       DbException.throwInternalError();
     }
     while (true) {
       if (needNewDelta) {
         loadNext(false);
         needNewDelta = false;
       }
       if (needNewBase) {
         loadNext(true);
         needNewBase = false;
       }
       if (deltaRow == null) {
         if (baseRow == null) {
           end = true;
           return false;
         }
         onBase = true;
         needNewBase = true;
         return true;
       }
       int sessionId = deltaRow.getSessionId();
       boolean isThisSession = sessionId == session.getId();
       boolean isDeleted = deltaRow.isDeleted();
       if (isThisSession && isDeleted) {
         needNewDelta = true;
         continue;
       }
       if (baseRow == null) {
         if (isDeleted) {
           if (isThisSession) {
             end = true;
             return false;
           }
           // the row was deleted by another session: return it
           onBase = false;
           needNewDelta = true;
           return true;
         }
         DbException.throwInternalError();
       }
       int compare = index.compareRows(deltaRow, baseRow);
       if (compare == 0) {
         // can't use compareKeys because the
         // version would be compared as well
         long k1 = deltaRow.getKey();
         long k2 = baseRow.getKey();
         compare = MathUtils.compareLong(k1, k2);
       }
       if (compare == 0) {
         if (isDeleted) {
           if (isThisSession) {
             DbException.throwInternalError();
           }
           // another session updated the row
         } else {
           if (isThisSession) {
             onBase = false;
             needNewBase = true;
             needNewDelta = true;
             return true;
           }
           // another session inserted the row: ignore
           needNewBase = true;
           needNewDelta = true;
           continue;
         }
       }
       if (compare > 0) {
         onBase = true;
         needNewBase = true;
         return true;
       }
       onBase = false;
       needNewDelta = true;
       return true;
     }
   }
 }
Example #11
0
 public Cursor find(Session session, SearchRow first, SearchRow last) {
   if (recursive) {
     if (view.getRecursiveResult() != null) {
       ResultInterface r = view.getRecursiveResult();
       r.reset();
       return new ViewCursor(table, r);
     }
     if (query == null) {
       query = (Query) createSession.prepare(querySQL, true);
       planSQL = query.getPlanSQL();
     }
     if (!(query instanceof SelectUnion)) {
       throw DbException.get(ErrorCode.SYNTAX_ERROR_2, "recursive queries without UNION ALL");
     }
     SelectUnion union = (SelectUnion) query;
     if (union.getUnionType() != SelectUnion.UNION_ALL) {
       throw DbException.get(ErrorCode.SYNTAX_ERROR_2, "recursive queries without UNION ALL");
     }
     Query left = union.getLeft();
     ResultInterface r = left.query(0);
     LocalResult result = union.getEmptyResult();
     while (r.next()) {
       result.addRow(r.currentRow());
     }
     Query right = union.getRight();
     r.reset();
     view.setRecursiveResult(r);
     while (true) {
       r = right.query(0);
       if (r.getRowCount() == 0) {
         break;
       }
       while (r.next()) {
         result.addRow(r.currentRow());
       }
       r.reset();
       view.setRecursiveResult(r);
     }
     return new ViewCursor(table, result);
   }
   ArrayList<Parameter> paramList = query.getParameters();
   for (int i = 0; originalParameters != null && i < originalParameters.size(); i++) {
     Parameter orig = originalParameters.get(i);
     int idx = orig.getIndex();
     Value value = orig.getValue(session);
     setParameter(paramList, idx, value);
   }
   int len;
   if (first != null) {
     len = first.getColumnCount();
   } else if (last != null) {
     len = last.getColumnCount();
   } else {
     len = 0;
   }
   int idx = originalParameters == null ? 0 : originalParameters.size();
   idx += view.getParameterOffset();
   for (int i = 0; i < len; i++) {
     if (first != null) {
       Value v = first.getValue(i);
       if (v != null) {
         int x = idx++;
         setParameter(paramList, x, v);
       }
     }
     // for equality, only one parameter is used (first == last)
     if (last != null && indexMasks[i] != IndexCondition.EQUALITY) {
       Value v = last.getValue(i);
       if (v != null) {
         int x = idx++;
         setParameter(paramList, x, v);
       }
     }
   }
   ResultInterface result = query.query(0);
   return new ViewCursor(table, result);
 }