예제 #1
0
 public void validationPlanItem(PlanItem item) {
   int priority = item.getScanningStrategy().priority;
   if (tableRule instanceof ShardedTableRule) {
     ShardedTableRule shardedTableRule = (ShardedTableRule) tableRule;
     switch (shardedTableRule.getScanLevel()) {
       case ShardedTableRule.SCANLEVEL_SHARDINGKEY:
         if (priority < ScanningStrategy.USE_SHARDINGKEY.priority) {
           throw DbException.get(
               ErrorCode.ALLOWED_SCANTABLE_ERROR, getName(), "shardingKey", "shardingKey");
         }
         break;
       case ShardedTableRule.SCANLEVEL_UNIQUEINDEX:
         if (priority < ScanningStrategy.USE_UNIQUEKEY.priority) {
           throw DbException.get(
               ErrorCode.ALLOWED_SCANTABLE_ERROR, getName(), "uniqueIndex", "uniqueIndex");
         }
         break;
       case ShardedTableRule.SCANLEVEL_ANYINDEX:
         if (priority < ScanningStrategy.USE_INDEXKEY.priority) {
           throw DbException.get(
               ErrorCode.ALLOWED_SCANTABLE_ERROR, getName(), "indexKey", "indexKey");
         }
         break;
       case ShardedTableRule.SCANLEVEL_UNLIMITED:
         break;
       default:
         throw DbException.throwInternalError("invalid scanLevel");
     }
   }
 }
예제 #2
0
  /**
   * Each shard have a database connection, the worker thread may concurrently use a shard
   * connection executing SQL (such as executing ddl statement), If the JDBC driver is
   * spec-compliant, then technically yes, the object is thread-safe, MySQL Connector/J, all methods
   * to execute statements lock the connection with a synchronized block.
   *
   * @param options
   * @return
   */
  protected Connection getConnectionWithStrategy(Options options) {
    String shardName = options.shardName;
    Connection conn;
    switch (holderStrategy) {
      case STRICTLY:
        if (connectionMap.isEmpty()) {
          conn = getRawConnection(options);
          connectionMap.put(shardName, conn);
        } else {
          conn = connectionMap.get(shardName);
          if (conn == null) {
            String lastTransactionNode = connectionMap.keySet().iterator().next();
            throw DbException.get(
                ErrorCode.GENERAL_ERROR_1,
                "STRICTLY transaction mode not supported operation on multi-node, opend on "
                    + lastTransactionNode
                    + " and try on "
                    + shardName);
          }
        }
        break;
      case ALLOW_CROSS_SHARD_READ:
        if (options.readOnly) {
          conn = connectionMap.get(shardName);
          if (conn == null) {
            conn = getRawConnectionForReadOnly(options);
          }
        } else {
          if (connectionMap.isEmpty()) {
            conn = getRawConnection(options);
            connectionMap.put(shardName, conn);
          } else {
            conn = connectionMap.get(shardName);
            if (conn == null) {
              String lastTransactionNode = connectionMap.keySet().iterator().next();
              throw DbException.get(
                  ErrorCode.GENERAL_ERROR_1,
                  "ALLOW_READ_CROSS_DB transaction mode not supported writing operation on multi-node, opend on "
                      + lastTransactionNode
                      + " and try on "
                      + shardName);
            }
          }
        }

        break;

      case BESTEFFORTS_1PC:
        conn = connectionMap.get(shardName);
        if (conn == null) {
          conn = getRawConnection(options);
          connectionMap.put(shardName, conn);
        }
        break;

      default:
        throw DbException.getInvalidValueException("transactionMode", holderStrategy);
    }
    return conn;
  }
예제 #3
0
 @Override
 public void prepare() {
   if (columns == null) {
     if (list.size() > 0 && list.get(0).length == 0) {
       // special case where table is used as a sequence
       columns = new Column[0];
     } else {
       columns = table.getColumns();
     }
   }
   if (list.size() > 0) {
     for (Expression[] expr : list) {
       if (expr.length != columns.length) {
         throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
       }
       for (int i = 0, len = expr.length; i < len; i++) {
         Expression e = expr[i];
         if (e != null) {
           e = e.optimize(session);
           if (e instanceof Parameter) {
             Parameter p = (Parameter) e;
             p.setColumn(columns[i]);
           }
           expr[i] = e;
         }
       }
     }
   } else {
     query.prepare();
     if (query.getColumnCount() != columns.length) {
       throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
     }
   }
 }
예제 #4
0
 /**
  * Keep a collection of the columns to pass to update if a duplicate key happens, for MySQL-style
  * INSERT ... ON DUPLICATE KEY UPDATE ....
  *
  * @param column the column
  * @param expression the expression
  */
 public void addAssignmentForDuplicate(Column column, Expression expression) {
   if (duplicateKeyAssignmentMap == null) {
     duplicateKeyAssignmentMap = New.hashMap();
   }
   if (duplicateKeyAssignmentMap.containsKey(column)) {
     throw DbException.get(ErrorCode.DUPLICATE_COLUMN_NAME_1, column.getName());
   }
   duplicateKeyAssignmentMap.put(column, expression);
 }
예제 #5
0
 @Override
 protected void doPrepare() {
   expressions = prepared.getExpressions();
   if (prepared.isGroupQuery()) {
     ArrayList<Expression> selectExprs = New.arrayList(10);
     int[] groupIndex = prepared.getGroupIndex();
     for (int i = 0; i < groupIndex.length; i++) {
       int idx = groupIndex[i];
       Expression expr = expressions.get(idx);
       selectExprs.add(expr);
     }
     HashSet<Aggregate> aggregates = New.hashSet();
     for (Expression expr : expressions) {
       expr.isEverything(ExpressionVisitor.getAggregateVisitor(aggregates));
     }
     selectExprs.addAll(aggregates);
     expressions = selectExprs;
   }
   Expression[] exprList = expressions.toArray(new Expression[expressions.size()]);
   Integer limit = null, offset = null;
   Expression limitExpr = prepared.getLimit();
   Expression offsetExpr = prepared.getOffset();
   if (limitExpr != null) {
     limit = limitExpr.getValue(session).getInt();
   }
   if (offsetExpr != null) {
     offset = offsetExpr.getValue(session).getInt();
   }
   RoutingResult rr = doRoute(prepared);
   if (rr.isMultipleNode() && offset != null) {
     if (offset > database.getSettings().analyzeSample) {
       throw DbException.get(
           ErrorCode.INVALID_VALUE_2,
           "offset",
           offset
               + ", the max support offset "
               + database.getSettings().analyzeSample
               + " is defined by analyzeSample.");
     }
     offset = offset != null ? 0 : offset;
   }
   ObjectNode[] selectNodes = rr.getSelectNodes();
   if (session.getDatabase().getSettings().optimizeMerging) {
     selectNodes = rr.group();
   }
   workers = New.arrayList(selectNodes.length);
   for (ObjectNode node : selectNodes) {
     QueryWorker queryHandler =
         queryHandlerFactory.createQueryWorker(
             prepared, node, consistencyTableNodes, exprList, limit, offset);
     workers.add(queryHandler);
   }
 }
예제 #6
0
 /** validation the rule columns is in the table columns */
 private void setRuleColumns() {
   if (tableRule instanceof ShardedTableRule) {
     ShardedTableRule shardedTableRule = (ShardedTableRule) tableRule;
     String[] ruleColNames = shardedTableRule.getRuleColumns();
     ruleColumns = new Column[ruleColNames.length];
     for (int i = 0; i < ruleColNames.length; i++) {
       String colName = database.identifier(ruleColNames[i]);
       if (!doesColumnExist(colName)) {
         throw DbException.get(ErrorCode.SHARDING_COLUMN_NOT_FOUND, colName, getName());
       }
       ruleColumns[i] = getColumn(colName);
     }
   }
 }
예제 #7
0
 /**
  * Convert a hex encoded string to a byte array.
  *
  * @param s the hex encoded string
  * @return the byte array
  */
 public static byte[] convertHexToBytes(String s) {
   int len = s.length();
   if (len % 2 != 0) {
     throw DbException.get(ErrorCode.HEX_STRING_ODD_1, s);
   }
   len /= 2;
   byte[] buff = new byte[len];
   int mask = 0;
   int[] hex = HEX_DECODE;
   try {
     for (int i = 0; i < len; i++) {
       int d = hex[s.charAt(i + i)] << 4 | hex[s.charAt(i + i + 1)];
       mask |= d;
       buff[i] = (byte) d;
     }
   } catch (ArrayIndexOutOfBoundsException e) {
     throw DbException.get(ErrorCode.HEX_STRING_WRONG_1, s);
   }
   if ((mask & ~255) != 0) {
     throw DbException.get(ErrorCode.HEX_STRING_WRONG_1, s);
   }
   return buff;
 }
예제 #8
0
 public void markDeleted() {
   Column[] cols = {};
   setColumns(cols);
   indexes.clear();
   initException = DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, this.getSQL());
 }
예제 #9
0
  private void tryReadMetaData(Connection conn, String oCatalog, String oSchema, String tableName)
      throws SQLException {

    DatabaseMetaData meta = conn.getMetaData();
    storesLowerCase = meta.storesLowerCaseIdentifiers();
    storesMixedCase = meta.storesMixedCaseIdentifiers();
    storesMixedCaseQuoted = meta.storesMixedCaseQuotedIdentifiers();
    supportsMixedCaseIdentifiers = meta.supportsMixedCaseIdentifiers();

    ResultSet rs = meta.getTables(oCatalog, oSchema, tableName, null);
    if (rs.next() && rs.next()) {
      throw DbException.get(ErrorCode.SCHEMA_NAME_MUST_MATCH, tableName);
    }
    rs.close();
    rs = meta.getColumns(null, null, tableName, null);
    int i = 0;
    ArrayList<Column> columnList = New.arrayList();
    HashMap<String, Column> columnMap = New.hashMap();
    String catalog = null, schema = null;
    while (rs.next()) {
      String thisCatalog = rs.getString("TABLE_CAT");
      if (catalog == null) {
        catalog = thisCatalog;
      }
      String thisSchema = rs.getString("TABLE_SCHEM");
      if (schema == null) {
        schema = thisSchema;
      }
      if (!StringUtils.equals(catalog, thisCatalog) || !StringUtils.equals(schema, thisSchema)) {
        // if the table exists in multiple schemas or tables,
        // use the alternative solution
        columnMap.clear();
        columnList.clear();
        break;
      }
      String n = rs.getString("COLUMN_NAME");
      n = convertColumnName(n);
      int sqlType = rs.getInt("DATA_TYPE");
      long precision = rs.getInt("COLUMN_SIZE");
      precision = convertPrecision(sqlType, precision);
      int scale = rs.getInt("DECIMAL_DIGITS");
      scale = convertScale(sqlType, scale);
      int displaySize = MathUtils.convertLongToInt(precision);
      int type = DataType.convertSQLTypeToValueType(sqlType);
      Column col = new Column(n, type, precision, scale, displaySize);
      col.setTable(this, i++);
      columnList.add(col);
      columnMap.put(n, col);
    }
    rs.close();
    // check if the table is accessible
    Statement stat = null;
    try {
      stat = conn.createStatement();
      rs = stat.executeQuery("SELECT * FROM " + tableName + " T WHERE 1=0");
      if (columnList.size() == 0) {
        // alternative solution
        ResultSetMetaData rsMeta = rs.getMetaData();
        for (i = 0; i < rsMeta.getColumnCount(); ) {
          String n = rsMeta.getColumnName(i + 1);
          n = convertColumnName(n);
          int sqlType = rsMeta.getColumnType(i + 1);
          long precision = rsMeta.getPrecision(i + 1);
          precision = convertPrecision(sqlType, precision);
          int scale = rsMeta.getScale(i + 1);
          scale = convertScale(sqlType, scale);
          int displaySize = rsMeta.getColumnDisplaySize(i + 1);
          int type = DataType.getValueTypeFromResultSet(rsMeta, i + 1);
          Column col = new Column(n, type, precision, scale, displaySize);
          col.setTable(this, i++);
          columnList.add(col);
          columnMap.put(n, col);
        }
      }
      rs.close();
    } catch (Exception e) {
      throw DbException.get(
          ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, e, tableName + "(" + e.toString() + ")");
    } finally {
      JdbcUtils.closeSilently(stat);
    }
    Column[] cols = new Column[columnList.size()];
    columnList.toArray(cols);
    setColumns(cols);
    // create scan index

    // load primary keys
    try {
      rs = meta.getPrimaryKeys(null, null, tableName);
    } catch (Exception e) {
      // Some ODBC bridge drivers don't support it:
      // some combinations of "DataDirect SequeLink(R) for JDBC"
      // http://www.datadirect.com/index.ssp
      rs = null;
    }
    String pkName = "";
    ArrayList<Column> list;
    if (rs != null && rs.next()) {
      // the problem is, the rows are not sorted by KEY_SEQ
      list = New.arrayList();
      do {
        int idx = rs.getInt("KEY_SEQ");
        if (pkName == null) {
          pkName = rs.getString("PK_NAME");
        }
        while (list.size() < idx) {
          list.add(null);
        }
        String col = rs.getString("COLUMN_NAME");
        col = convertColumnName(col);
        Column column = columnMap.get(col);
        if (idx == 0) {
          // workaround for a bug in the SQLite JDBC driver
          list.add(column);
        } else {
          list.set(idx - 1, column);
        }
      } while (rs.next());
      addIndex(pkName, list, IndexType.createPrimaryKey(false));
      rs.close();
    }

    try {
      rs = meta.getIndexInfo(null, null, tableName, false, true);
    } catch (Exception e) {
      // Oracle throws an exception if the table is not found or is a
      // SYNONYM
      rs = null;
    }
    String indexName = null;
    list = New.arrayList();
    IndexType indexType = null;
    if (rs != null) {
      while (rs.next()) {
        if (rs.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic) {
          // ignore index statistics
          continue;
        }
        String newIndex = rs.getString("INDEX_NAME");
        if (pkName.equals(newIndex)) {
          continue;
        }
        if (indexName != null && !indexName.equals(newIndex)) {
          addIndex(indexName, list, indexType);
          indexName = null;
        }
        if (indexName == null) {
          indexName = newIndex;
          list.clear();
        }
        boolean unique = !rs.getBoolean("NON_UNIQUE");
        indexType = unique ? IndexType.createUnique(false) : IndexType.createNonUnique();
        String col = rs.getString("COLUMN_NAME");
        col = convertColumnName(col);
        Column column = columnMap.get(col);
        list.add(column);
      }
      rs.close();
    }
    if (indexName != null) {
      addIndex(indexName, list, indexType);
    }
    shardingKeyIndex();
  }
예제 #10
0
 private static DbException getFormatException(String s, int i) {
   return DbException.get(ErrorCode.STRING_FORMAT_ERROR_1, addAsterisk(s, i));
 }