예제 #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
 @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);
     }
   }
 }
예제 #3
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;
  }
예제 #4
0
 private RoutingResult doRoute(Select prepare) {
   List<TableFilter> filters = filterNotTableMate(prepare.getTopTableFilter());
   List<TableFilter> shards = New.arrayList(filters.size());
   List<TableFilter> globals = New.arrayList(filters.size());
   List<TableFilter> fixeds = New.arrayList(filters.size());
   for (TableFilter tf : filters) {
     TableMate table = getTableMate(tf);
     switch (table.getTableRule().getType()) {
       case TableRule.SHARDED_NODE_TABLE:
         shards.add(tf);
         break;
       case TableRule.GLOBAL_NODE_TABLE:
         globals.add(tf);
         break;
       case TableRule.FIXED_NODE_TABLE:
         fixeds.add(tf);
         break;
       default:
         break;
     }
   }
   RoutingResult result = null;
   if (!shards.isEmpty()) {
     for (TableFilter f : shards) {
       f.setEvaluatable(f, false);
       if (f.isJoinOuter() || f.isJoinOuterIndirect()) {
         prepare.getCondition().createIndexConditions(session, f);
       }
       TableMate table = getTableMate(f);
       ConditionExtractor extractor = new ConditionExtractor(f);
       RoutingResult r =
           routingHandler.doRoute(
               table, extractor.getStart(), extractor.getEnd(), extractor.getInColumns());
       result = (result == null || r.compareTo(result) < 0) ? r : result;
     }
     for (TableFilter f : shards) {
       f.setEvaluatable(f, true);
     }
   } else if (!fixeds.isEmpty()) {
     for (TableFilter tf : shards) {
       TableMate table = getTableMate(tf);
       RoutingResult r = routingHandler.doRoute(table);
       result = r;
     }
   } else if (!globals.isEmpty()) {
     // 全部为全局表查询,随机取一个第一个表结点
     GlobalTableRule tableRule = (GlobalTableRule) getTableRule(globals.iterator().next());
     RoutingResult r = tableRule.getRandomRoutingResult();
     result = r;
   } else {
     throw DbException.throwInternalError("SQL_ROUTING_ERROR");
   }
   ObjectNode[] selectNodes = result.getSelectNodes();
   if (selectNodes.length == 0) {
     throw DbException.throwInternalError("SQL_ROUTING_ERROR,empty result");
   }
   setConsistencyTableNodes(selectNodes, filters);
   return result;
 }
예제 #5
0
 /** @param session */
 public void readMataData(Session session, ObjectNode matadataNode) {
   for (int retry = 0; ; retry++) {
     try {
       Connection conn = null;
       String shardName = matadataNode.getShardName();
       String tableName = matadataNode.getQualifiedObjectName();
       String catalog = matadataNode.getCatalog();
       String schema = matadataNode.getSchema();
       try {
         JdbcRepository dsRepository = (JdbcRepository) database.getRepository();
         DataSource dataSource = dsRepository.getDataSourceByShardName(shardName);
         conn = dataSource.getConnection();
         tableName = database.identifier(tableName);
         if (catalog != null) {
           catalog = database.identifier(catalog);
         }
         if (schema != null) {
           schema = database.identifier(schema);
         }
         tryReadMetaData(conn, catalog, schema, tableName);
         return;
       } catch (Exception e) {
         throw DbException.convert(e);
       } finally {
         JdbcUtils.closeSilently(conn);
       }
     } catch (DbException e) {
       if (retry >= MAX_RETRY) {
         throw e;
       }
     }
   }
 }
예제 #6
0
 /**
  * Remove the row from the result set if it exists.
  *
  * @param values the row
  */
 public void removeDistinct(Value[] values) {
   if (!distinct) {
     DbException.throwInternalError();
   }
   ValueArray array = ValueArray.get(values);
   distinctRows.remove(array);
   rowCount = distinctRows.size();
 }
예제 #7
0
 /**
  * Encode the string as an URL.
  *
  * @param s the string to encode
  * @return the encoded string
  */
 public static String urlEncode(String s) {
   try {
     return URLEncoder.encode(s, "UTF-8");
   } catch (Exception e) {
     // UnsupportedEncodingException
     throw DbException.convert(e);
   }
 }
예제 #8
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);
 }
예제 #9
0
 /**
  * Add a row to this object.
  *
  * @param values the row to add
  */
 @Override
 public void addRow(Value[] values) {
   cloneLobs(values);
   if (distinct) {
     ValueArray array = getArrayOfVisible(values);
     distinctRows.put(array, values);
     rowCount = distinctRows.size();
     if (rowCount > maxMemoryRows) {
       throw DbException.getUnsupportedException("too big result row " + maxMemoryRows);
     }
     return;
   }
   rows.add(values);
   rowCount++;
   if (rows.size() > maxMemoryRows) {
     throw DbException.getUnsupportedException("too big result row " + maxMemoryRows);
   }
 }
예제 #10
0
 private HolderStrategy transactionMode(String mode) {
   try {
     HolderStrategy holderStrategy =
         StringUtils.isNullOrEmpty(mode)
             ? HolderStrategy.BESTEFFORTS_1PC
             : HolderStrategy.valueOf(mode);
     return holderStrategy;
   } catch (Exception e) {
     throw DbException.getInvalidValueException("transactionMode", mode);
   }
 }
예제 #11
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);
   }
 }
예제 #12
0
 public synchronized <T> List<T> foreach(Callback<T> callback) throws DbException {
   List<T> results = New.arrayList();
   for (String name : connectionMap.keySet()) {
     try {
       Connection conn = connectionMap.get(name);
       results.add(callback.handle(name, conn));
     } catch (SQLException e) {
       trace.error(e, "foreach {0} connection error", name);
       throw DbException.convert(e);
     }
   }
   return results;
 }
예제 #13
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);
     }
   }
 }
예제 #14
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;
 }
예제 #15
0
 private Connection getRawConnectionForReadOnly(Options options) {
   try {
     Connection conn = target.getConnection(options);
     conn.setAutoCommit(true);
     conn.setReadOnly(true);
     if (session.getTransactionIsolation() != 0) {
       if (conn.getTransactionIsolation() != session.getTransactionIsolation()) {
         conn.setTransactionIsolation(session.getTransactionIsolation());
       }
     }
     return conn;
   } catch (SQLException e) {
     throw DbException.convert(e);
   }
 }
예제 #16
0
 public void loadMataData(Session session) {
   ObjectNode node = tableRule.getMetadataNode();
   String tableName = node.getCompositeObjectName();
   String shardName = node.getShardName();
   try {
     trace.debug("Try to load {0} metadata from table {1}.{2}", getName(), shardName, tableName);
     readMataData(session, node);
     trace.debug("Load the {0} metadata success.", getName());
     initException = null;
   } catch (DbException e) {
     if (e.getErrorCode() == ErrorCode.COLUMN_NOT_FOUND_1) {
       throw e;
     }
     trace.debug(
         "Fail to load {0} metadata from table {1}.{2}. error: {3}",
         getName(), shardName, tableName, e.getCause().getMessage());
     initException = e;
     Column[] cols = {};
     setColumns(cols);
   }
   if (isInited()) {
     setRuleColumns();
   }
 }
예제 #17
0
 /**
  * Construct a local result set by reading all data from a regular result set.
  *
  * @param session the session
  * @param rs the result set
  * @param maxrows the maximum number of rows to read (0 for no limit)
  * @return the local result set
  */
 public static LocalResult read(Session session, ResultSet rs, int maxrows) {
   Expression[] cols = Expression.getExpressionColumns(session, rs);
   int columnCount = cols.length;
   LocalResult result = new LocalResult(session, cols, columnCount);
   try {
     for (int i = 0; (maxrows == 0 || i < maxrows) && rs.next(); i++) {
       Value[] list = new Value[columnCount];
       for (int j = 0; j < columnCount; j++) {
         int type = result.getColumnType(j);
         list[j] = DataType.readValue(rs, j + 1, type);
       }
       result.addRow(list);
     }
   } catch (SQLException e) {
     throw DbException.convert(e);
   }
   result.done();
   return result;
 }
예제 #18
0
 /**
  * @param options
  * @return
  * @throws SQLException
  */
 private Connection getRawConnection(Options options) throws DbException {
   Connection conn = target.getConnection(options);
   try {
     if (conn.getAutoCommit() != session.getAutoCommit()) {
       conn.setAutoCommit(session.getAutoCommit());
     }
     if (session.getTransactionIsolation() != 0) {
       if (conn.getTransactionIsolation() != session.getTransactionIsolation()) {
         conn.setTransactionIsolation(session.getTransactionIsolation());
       }
     }
     if (conn.isReadOnly() != session.isReadOnly()) {
       conn.setReadOnly(session.isReadOnly());
     }
   } catch (Exception e) {
     throw DbException.convert(e);
   }
   return conn;
 }
예제 #19
0
 @Override
 public boolean previous() {
   throw DbException.throwInternalError();
 }
예제 #20
0
 public void markDeleted() {
   Column[] cols = {};
   setColumns(cols);
   indexes.clear();
   initException = DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, this.getSQL());
 }
예제 #21
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();
  }
예제 #22
0
 private static DbException getFormatException(String s, int i) {
   return DbException.get(ErrorCode.STRING_FORMAT_ERROR_1, addAsterisk(s, i));
 }