/** * Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com). * * 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. */ package com.jfinal.plugin.activerecord; import java.util.LinkedList; /** * PageSqlKit */ public class PageSqlKit { private static final int start = "select ".length(); private static final char NULL = 0; private static final char SIZE = 128; private static char[] charTable = buildCharTable(); private static char[] buildCharTable() { char[] ret = new char[SIZE]; for (char i=0; i<SIZE; i++) { ret[i] = NULL; } ret['('] = '('; ret[')'] = ')'; ret['f'] = 'f'; ret['F'] = 'f'; ret['r'] = 'r'; ret['R'] = 'r'; ret['o'] = 'o'; ret['O'] = 'o'; ret['m'] = 'm'; ret['M'] = 'm'; ret[' '] = ' '; ret['\r'] = ' '; ret['\n'] = ' '; ret['\t'] = ' '; return ret; } /** * 未来考虑处理字符串常量中的字符: * 1:select * from article where title = 'select * from' * 此例可以正常处理,因为在第一个 from 之处就会正确返回 * * 2:select (select x from t where y = 'select * from ...') as a from article * 此例无法正常处理,暂时交由 paginateByFullSql(...) * * 3:如果一定要处理上例中的问题,还要了解不同数据库有关字符串常量的定界符细节 */ private static int getIndexOfFrom(String sql) { LinkedList<String> stack = null; char c; for (int i = start, end = sql.length() - 5; i < end; i++) { c = sql.charAt(i); if (c >= SIZE) { continue ; } c = charTable[c]; if (c == NULL) { continue ; } if (c == '(') { if (stack == null) { stack = new LinkedList<String>(); } stack.push("("); continue ; } if (c == ')') { if (stack == null) { throw new RuntimeException("Can not match left paren '(' for right paren ')': " + sql); } stack.pop(); continue ; } if (stack != null && !stack.isEmpty()) { continue ; } if (c == 'f' && charTable[sql.charAt(i + 1)] == 'r' && charTable[sql.charAt(i + 2)] == 'o' && charTable[sql.charAt(i + 3)] == 'm') { c = sql.charAt(i + 4); // 测试用例: "select count(*)from(select * from account limit 3) as t" if (charTable[c] == ' ' || c == '(') { // 判断 from 后方字符 c = sql.charAt(i - 1); if (charTable[c] == ' ' || c == ')') { // 判断 from 前方字符 return i; } } } } return -1; } public static String[] parsePageSql(String sql) { int index = getIndexOfFrom(sql); if (index == -1) { return null; } String[] ret = new String[2]; ret[0] = sql.substring(0, index); ret[1] = sql.substring(index); return ret; } }