/* * Copyright 1999-2012 Alibaba Group. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * (created at 2011-8-3) */ package com.alibaba.cobar.route.hint; import java.sql.SQLSyntaxErrorException; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.alibaba.cobar.parser.util.Pair; import com.alibaba.cobar.route.RouteResultsetNode; /** * @author <a href="mailto:shuo.qius@alibaba-inc.com">QIU Shuo</a> */ public final class CobarHint { // index start from 1 // /*!cobar: $dataNodeId=0.0, $table='offer'*/ // /*!cobar: $dataNodeId=[0,1,5.2], $table='offer'*/ // /*!cobar: $partitionOperand=('member_id'='m1'), $table='offer'*/ // /*!cobar: $partitionOperand=('member_id'=['m1','m2']), $table='offer', // $replica=2*/ // /*!cobar: $partitionOperand=(['offer_id','group_id']=[123,'3c']), // $table='offer'*/ // /*!cobar: // $partitionOperand=(['offer_id','group_id']=[[123,'3c'],[234,'food']]), // $table='offer'*/ public static final String COBAR_HINT_PREFIX = "/*!cobar:"; private static final Map<String, HintParser> HINT_PARSERS = new HashMap<String, HintParser>(); { HINT_PARSERS.put("table", new SimpleHintParser()); HINT_PARSERS.put("replica", new SimpleHintParser()); HINT_PARSERS.put("dataNodeId", new DataNodeHintParser()); HINT_PARSERS.put("partitionOperand", new PartitionOperandHintParser()); } private int replica = RouteResultsetNode.DEFAULT_REPLICA_INDEX; private String table; private List<Pair<Integer, Integer>> dataNodes; private Pair<String[], Object[][]> partitionOperand; /** * @param offset index of first char of {@link #COBAR_HINT_PREFIX} */ public static CobarHint parserCobarHint(String sql, int offset) throws SQLSyntaxErrorException { CobarHint hint = new CobarHint(); hint.currentIndex = offset + COBAR_HINT_PREFIX.length(); hint.parse(sql); return hint; } /** * @return String[] in upper-case */ public Pair<String[], Object[][]> getPartitionOperand() { return partitionOperand; } public void setPartitionOperand(Pair<String[], Object[][]> partitionOperand) { String[] columns = partitionOperand.getKey(); if (columns == null) { this.partitionOperand = partitionOperand; } else { String[] colUp = new String[columns.length]; for (int i = 0; i < columns.length; ++i) { colUp[i] = columns[i].toUpperCase(); } this.partitionOperand = new Pair<String[], Object[][]>(colUp, partitionOperand.getValue()); } } public List<Pair<Integer, Integer>> getDataNodes() { return dataNodes; } public void addDataNode(Integer dataNodeIndex, Integer replica) { if (dataNodeIndex == null) { throw new IllegalArgumentException("data node index is null"); } if (replica == RouteResultsetNode.DEFAULT_REPLICA_INDEX || replica < 0) { replica = null; } if (dataNodes == null) { dataNodes = new LinkedList<Pair<Integer, Integer>>(); } dataNodes.add(new Pair<Integer, Integer>(dataNodeIndex, replica)); } /** * @return upper case */ public String getTable() { return table; } public void setTable(String table) { this.table = table.toUpperCase(); } public int getReplica() { return replica; } public void setReplica(int replica) { this.replica = replica; } private void parse(String sql) throws SQLSyntaxErrorException { cobarHint: for (;;) { skip: for (;;) { switch (sql.charAt(currentIndex)) { case '$': break skip; case '*': currentIndex += 2; break cobarHint; default: ++currentIndex; } } int hintNameEnd = sql.indexOf('=', currentIndex); String hintName = sql.substring(currentIndex + 1, hintNameEnd).trim(); HintParser hintParser = HINT_PARSERS.get(hintName); if (hintParser != null) { currentIndex = 1 + sql.indexOf('=', hintNameEnd); hintParser.process(this, hintName, sql); } else { throw new SQLSyntaxErrorException("unrecognized hint name: ${" + hintName + "}"); } } outputSql = sql.substring(currentIndex); } private String outputSql; private int currentIndex; public int getCurrentIndex() { return currentIndex; } public CobarHint increaseCurrentIndex() { ++currentIndex; return this; } public void setCurrentIndex(int ci) { currentIndex = ci; } public String getOutputSql() { return outputSql; } }