AbstractInsertParser.java 8.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright 1999-2015 dangdang.com.
 * <p>
 * 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.
 * </p>
 */
T
terrymanu 已提交
17

18
package com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.insert;
19

T
terrymanu 已提交
20
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
21
import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException;
T
terrymanu 已提交
22 23 24 25
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.Assist;
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.DefaultKeyword;
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.Symbol;
import com.dangdang.ddframe.rdb.sharding.parsing.lexer.token.TokenType;
T
terrymanu 已提交
26
import com.dangdang.ddframe.rdb.sharding.parsing.parser.SQLParser;
27
import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.GeneratedKey;
T
terrymanu 已提交
28
import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.condition.Column;
T
terrymanu 已提交
29
import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.condition.Condition;
30
import com.dangdang.ddframe.rdb.sharding.parsing.parser.exception.SQLParsingUnsupportedException;
T
terrymanu 已提交
31 32 33
import com.dangdang.ddframe.rdb.sharding.parsing.parser.expression.SQLExpression;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.expression.SQLNumberExpression;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.expression.SQLPlaceholderExpression;
T
terrymanu 已提交
34
import com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.SQLStatementParser;
35
import com.dangdang.ddframe.rdb.sharding.parsing.parser.token.GeneratedKeyToken;
36
import com.dangdang.ddframe.rdb.sharding.parsing.parser.token.ItemsToken;
37
import com.dangdang.ddframe.rdb.sharding.util.SQLUtil;
38
import com.google.common.base.Optional;
T
terrymanu 已提交
39
import com.google.common.collect.Sets;
T
terrymanu 已提交
40
import lombok.AccessLevel;
T
terrymanu 已提交
41 42
import lombok.Getter;

43
import java.util.Collection;
T
terrymanu 已提交
44
import java.util.Collections;
45 46
import java.util.LinkedList;
import java.util.List;
T
terrymanu 已提交
47 48 49 50 51 52 53
import java.util.Set;

/**
 * Insert语句解析器.
 *
 * @author zhangliang
 */
T
terrymanu 已提交
54
@Getter(AccessLevel.PROTECTED)
T
terrymanu 已提交
55
public abstract class AbstractInsertParser implements SQLStatementParser {
T
terrymanu 已提交
56
    
T
terrymanu 已提交
57
    private final SQLParser sqlParser;
T
terrymanu 已提交
58
    
59 60
    private final ShardingRule shardingRule;
    
61
    private final InsertStatement insertStatement;
T
terrymanu 已提交
62
    
T
terrymanu 已提交
63
    @Getter(AccessLevel.NONE)
64 65
    private int generateKeyColumnIndex = -1;
    
T
terrymanu 已提交
66
    public AbstractInsertParser(final ShardingRule shardingRule, final SQLParser sqlParser) {
T
terrymanu 已提交
67
        this.sqlParser = sqlParser;
68
        this.shardingRule = shardingRule;
69
        insertStatement = new InsertStatement();
T
terrymanu 已提交
70 71
    }
    
T
terrymanu 已提交
72
    @Override
73
    public final InsertStatement parse() {
T
terrymanu 已提交
74
        sqlParser.getLexer().nextToken();
T
terrymanu 已提交
75
        parseInto();
76
        parseColumns();
T
terrymanu 已提交
77
        if (sqlParser.equalAny(DefaultKeyword.SELECT, Symbol.LEFT_PAREN)) {
T
terrymanu 已提交
78 79
            throw new UnsupportedOperationException("Cannot support subquery");
        }
T
terrymanu 已提交
80
        if (getValuesKeywords().contains(sqlParser.getLexer().getCurrentToken().getType())) {
81
            parseValues();
T
terrymanu 已提交
82
        } else if (getCustomizedInsertKeywords().contains(sqlParser.getLexer().getCurrentToken().getType())) {
T
terrymanu 已提交
83
            parseCustomizedInsert();
T
terrymanu 已提交
84
        }
85
        appendGenerateKey();
86
        return insertStatement;
T
terrymanu 已提交
87 88
    }
    
T
terrymanu 已提交
89
    protected Set<TokenType> getUnsupportedKeywords() {
T
terrymanu 已提交
90 91 92
        return Collections.emptySet();
    }
    
T
terrymanu 已提交
93
    private void parseInto() {
T
terrymanu 已提交
94 95
        if (getUnsupportedKeywords().contains(sqlParser.getLexer().getCurrentToken().getType())) {
            throw new SQLParsingUnsupportedException(sqlParser.getLexer().getCurrentToken().getType());
T
terrymanu 已提交
96
        }
T
terrymanu 已提交
97 98
        sqlParser.skipUntil(DefaultKeyword.INTO);
        sqlParser.getLexer().nextToken();
99
        sqlParser.parseSingleTable(insertStatement);
T
terrymanu 已提交
100
        skipBetweenTableAndValues();
101 102
    }
    
T
terrymanu 已提交
103
    private void skipBetweenTableAndValues() {
T
terrymanu 已提交
104 105 106 107
        while (getSkippedKeywordsBetweenTableAndValues().contains(sqlParser.getLexer().getCurrentToken().getType())) {
            sqlParser.getLexer().nextToken();
            if (sqlParser.equalAny(Symbol.LEFT_PAREN)) {
                sqlParser.skipParentheses();
T
terrymanu 已提交
108 109
            }
        }
T
terrymanu 已提交
110 111
    }
    
T
terrymanu 已提交
112
    protected Set<TokenType> getSkippedKeywordsBetweenTableAndValues() {
113 114 115
        return Collections.emptySet();
    }
    
116
    private void parseColumns() {
T
terrymanu 已提交
117
        Collection<Column> result = new LinkedList<>();
T
terrymanu 已提交
118
        if (sqlParser.equalAny(Symbol.LEFT_PAREN)) {
T
terrymanu 已提交
119
            String tableName = insertStatement.getTables().getSingleTableName();
120 121
            Optional<String> generateKeyColumn = shardingRule.getGenerateKeyColumn(tableName);
            int count = 0;
122
            do {
T
terrymanu 已提交
123
                sqlParser.getLexer().nextToken();
124
                String columnName = SQLUtil.getExactlyValue(sqlParser.getLexer().getCurrentToken().getLiterals());
T
terrymanu 已提交
125
                result.add(new Column(columnName, tableName));
T
terrymanu 已提交
126
                sqlParser.getLexer().nextToken();
127 128 129 130
                if (generateKeyColumn.isPresent() && generateKeyColumn.get().equalsIgnoreCase(columnName)) {
                    generateKeyColumnIndex = count;
                }
                count++;
T
terrymanu 已提交
131
            } while (!sqlParser.equalAny(Symbol.RIGHT_PAREN) && !sqlParser.equalAny(Assist.END));
132
            insertStatement.setColumnsListLastPosition(sqlParser.getLexer().getCurrentToken().getEndPosition() - sqlParser.getLexer().getCurrentToken().getLiterals().length());
T
terrymanu 已提交
133
            sqlParser.getLexer().nextToken();
T
terrymanu 已提交
134
        }
T
terrymanu 已提交
135
        insertStatement.getColumns().addAll(result);
T
terrymanu 已提交
136 137
    }
    
T
terrymanu 已提交
138 139
    protected Set<TokenType> getValuesKeywords() {
        return Sets.<TokenType>newHashSet(DefaultKeyword.VALUES);
140 141
    }
    
142
    private void parseValues() {
143
        boolean parsed = false;
144
        do {
145 146 147
            if (parsed) {
                throw new UnsupportedOperationException("Cannot support multiple insert");
            }
T
terrymanu 已提交
148 149
            sqlParser.getLexer().nextToken();
            sqlParser.accept(Symbol.LEFT_PAREN);
T
terrymanu 已提交
150
            List<SQLExpression> sqlExpressions = new LinkedList<>();
151
            do {
T
terrymanu 已提交
152
                sqlExpressions.add(sqlParser.parseExpression());
T
terrymanu 已提交
153
            } while (sqlParser.skipIfEqual(Symbol.COMMA));
154
            insertStatement.setValuesListLastPosition(sqlParser.getLexer().getCurrentToken().getEndPosition() - sqlParser.getLexer().getCurrentToken().getLiterals().length());
155
            int count = 0;
T
terrymanu 已提交
156
            for (Column each : insertStatement.getColumns()) {
T
terrymanu 已提交
157
                SQLExpression sqlExpression = sqlExpressions.get(count);
T
terrymanu 已提交
158
                insertStatement.getConditions().add(new Condition(each, sqlExpression), shardingRule);
159
                if (generateKeyColumnIndex == count) {
T
terrymanu 已提交
160
                    insertStatement.setGeneratedKey(createGeneratedKey(each, sqlExpression));
161
                }
162 163
                count++;
            }
T
terrymanu 已提交
164
            sqlParser.accept(Symbol.RIGHT_PAREN);
165
            parsed = true;
166
        }
T
terrymanu 已提交
167
        while (sqlParser.equalAny(Symbol.COMMA));
T
terrymanu 已提交
168 169
    }
    
T
terrymanu 已提交
170
    private GeneratedKey createGeneratedKey(final Column column, final SQLExpression sqlExpression) {
171
        GeneratedKey result;
T
terrymanu 已提交
172
        if (sqlExpression instanceof SQLPlaceholderExpression) {
T
terrymanu 已提交
173
            result = new GeneratedKey(column.getName(), ((SQLPlaceholderExpression) sqlExpression).getIndex(), null);
T
terrymanu 已提交
174
        } else if (sqlExpression instanceof SQLNumberExpression) {
T
terrymanu 已提交
175
            result = new GeneratedKey(column.getName(), -1, ((SQLNumberExpression) sqlExpression).getNumber());
176 177 178 179 180 181
        } else {
            throw new ShardingJdbcException("Generated key only support number.");
        }
        return result;
    }
    
T
terrymanu 已提交
182
    protected Set<TokenType> getCustomizedInsertKeywords() {
T
terrymanu 已提交
183 184 185
        return Collections.emptySet();
    }
    
T
terrymanu 已提交
186
    protected void parseCustomizedInsert() {
T
terrymanu 已提交
187
    }
188
    
189
    private void appendGenerateKey() {
T
terrymanu 已提交
190
        String tableName = insertStatement.getTables().getSingleTableName();
191
        Optional<String> generateKeyColumn = shardingRule.getGenerateKeyColumn(tableName);
192
        if (!generateKeyColumn.isPresent() || null != insertStatement.getGeneratedKey()) {
193 194
            return;
        } 
195
        ItemsToken columnsToken = new ItemsToken(insertStatement.getColumnsListLastPosition());
196
        columnsToken.getItems().add(generateKeyColumn.get());
197 198
        insertStatement.getSqlTokens().add(columnsToken);
        insertStatement.getSqlTokens().add(new GeneratedKeyToken(insertStatement.getValuesListLastPosition()));
199
    }
T
terrymanu 已提交
200
}