/*
* Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software;Designed and Developed mainly by many Chinese
* opensource volunteers. you can redistribute it and/or modify it under the
* terms of the GNU General Public License version 2 only, as published by the
* Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Any questions about this component can be directed to it's project Web address
* https://code.google.com/p/opencloudb/.
*
*/
package org.opencloudb.parser.util;
/**
* @author mycat
*/
public final class ParseUtil {
public static boolean isEOF(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == ';');
}
public static long getSQLId(String stmt) {
int offset = stmt.indexOf('=');
if (offset != -1 && stmt.length() > ++offset) {
String id = stmt.substring(offset).trim();
try {
return Long.parseLong(id);
} catch (NumberFormatException e) {
}
}
return 0L;
}
/**
* <code>'abc'</code>
*
* @param offset stmt.charAt(offset) == first <code>'</code>
*/
private static String parseString(String stmt, int offset) {
StringBuilder sb = new StringBuilder();
loop: for (++offset; offset < stmt.length(); ++offset) {
char c = stmt.charAt(offset);
if (c == '\\') {
switch (c = stmt.charAt(++offset)) {
case '0':
sb.append('\0');
break;
case 'b':
sb.append('\b');
break;
case 'n':
sb.append('\n');
break;
case 'r':
sb.append('\r');
break;
case 't':
sb.append('\t');
break;
case 'Z':
sb.append((char) 26);
break;
default:
sb.append(c);
}
} else if (c == '\'') {
if (offset + 1 < stmt.length() && stmt.charAt(offset + 1) == '\'') {
++offset;
sb.append('\'');
} else {
break loop;
}
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* <code>"abc"</code>
*
* @param offset stmt.charAt(offset) == first <code>"</code>
*/
private static String parseString2(String stmt, int offset) {
StringBuilder sb = new StringBuilder();
loop: for (++offset; offset < stmt.length(); ++offset) {
char c = stmt.charAt(offset);
if (c == '\\') {
switch (c = stmt.charAt(++offset)) {
case '0':
sb.append('\0');
break;
case 'b':
sb.append('\b');
break;
case 'n':
sb.append('\n');
break;
case 'r':
sb.append('\r');
break;
case 't':
sb.append('\t');
break;
case 'Z':
sb.append((char) 26);
break;
default:
sb.append(c);
}
} else if (c == '"') {
if (offset + 1 < stmt.length() && stmt.charAt(offset + 1) == '"') {
++offset;
sb.append('"');
} else {
break loop;
}
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* <code>AS `abc`</code>
*
* @param offset stmt.charAt(offset) == first <code>`</code>
*/
private static String parseIdentifierEscape(String stmt, int offset) {
StringBuilder sb = new StringBuilder();
loop: for (++offset; offset < stmt.length(); ++offset) {
char c = stmt.charAt(offset);
if (c == '`') {
if (offset + 1 < stmt.length() && stmt.charAt(offset + 1) == '`') {
++offset;
sb.append('`');
} else {
break loop;
}
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* @param aliasIndex for <code>AS id</code>, index of 'i'
*/
public static String parseAlias(String stmt, final int aliasIndex) {
if (aliasIndex < 0 || aliasIndex >= stmt.length()) {
return null;
}
switch (stmt.charAt(aliasIndex)) {
case '\'':
return parseString(stmt, aliasIndex);
case '"':
return parseString2(stmt, aliasIndex);
case '`':
return parseIdentifierEscape(stmt, aliasIndex);
default:
int offset = aliasIndex;
for (; offset < stmt.length() && CharTypes.isIdentifierChar(stmt.charAt(offset)); ++offset);
return stmt.substring(aliasIndex, offset);
}
}
public static int comment(String stmt, int offset) {
int len = stmt.length();
int n = offset;
switch (stmt.charAt(n)) {
case '/':
if (len > ++n && stmt.charAt(n++) == '*' && len > n + 1 && stmt.charAt(n) != '!') {
for (int i = n; i < len; ++i) {
if (stmt.charAt(i) == '*') {
int m = i + 1;
if (len > m && stmt.charAt(m) == '/') return m;
}
}
}
break;
case '#':
for (int i = n + 1; i < len; ++i) {
if (stmt.charAt(i) == '\n') return i;
}
break;
}
return offset;
}
public static boolean currentCharIsSep(String stmt, int offset) {
if (stmt.length() > offset) {
switch (stmt.charAt(offset)) {
case ' ':
case '\t':
case '\r':
case '\n':
return true;
default:
return false;
}
}
return true;
}
/*****
* 检查下一个字符是否为分隔符,并把偏移量加1
*/
public static boolean nextCharIsSep(String stmt, int offset) {
return currentCharIsSep(stmt, ++offset);
}
/*****
* 检查下一个字符串是否为期望的字符串,并把偏移量移到从offset开始计算,expectValue之后的位置
*
* @param stmt 被解析的sql
* @param offset 被解析的sql的当前位置
* @param nextExpectedString 在stmt中准备查找的字符串
* @param checkSepChar 当找到expectValue值时,是否检查其后面字符为分隔符号
* @return 如果包含指定的字符串,则移动相应的偏移量,否则返回值=offset
*/
public static int nextStringIsExpectedWithIgnoreSepChar(String stmt,
int offset,
String nextExpectedString,
boolean checkSepChar) {
if (nextExpectedString == null || nextExpectedString.length() < 1) return offset;
int i = offset;
int index = 0;
char expectedChar;
char actualChar;
boolean isSep;
for (; i < stmt.length() && index < nextExpectedString.length(); ++i) {
if (index == 0) {
isSep = currentCharIsSep(stmt, i);
if (isSep) {
continue;
}
}
actualChar = stmt.charAt(i);
expectedChar = nextExpectedString.charAt(index++);
if (actualChar != expectedChar) {
return offset;
}
}
if (index == nextExpectedString.length()) {
boolean ok = true;
if (checkSepChar) {
ok = nextCharIsSep(stmt, i);
}
if (ok) return i;
}
return offset;
}
private static final String JSON = "json";
private static final String EQ = "=";
//private static final String WHERE = "where";
//private static final String SET = "set";
/**********
* 检查下一个字符串是否json= *
*
* @param stmt 被解析的sql
* @param offset 被解析的sql的当前位置
* @return 如果包含指定的字符串,则移动相应的偏移量,否则返回值=offset
*/
public static int nextStringIsJsonEq(String stmt, int offset) {
int i = offset;
// / drds 之后的符号
if (!currentCharIsSep(stmt, ++i)) {
return offset;
}
// json 串
int k = nextStringIsExpectedWithIgnoreSepChar(stmt, i, JSON, false);
if (k <= i) {
return offset;
}
i = k;
// 等于符号
k = nextStringIsExpectedWithIgnoreSepChar(stmt, i, EQ, false);
if (k <= i) {
return offset;
}
return i;
}
public static int move(String stmt, int offset, int length) {
int i = offset;
for (; i < stmt.length(); ++i) {
switch (stmt.charAt(i)) {
case ' ':
case '\t':
case '\r':
case '\n':
continue;
case '/':
case '#':
i = comment(stmt, i);
continue;
default:
return i + length;
}
}
return i;
}
public static boolean compare(String s, int offset, char[] keyword) {
if (s.length() >= offset + keyword.length) {
for (int i = 0; i < keyword.length; ++i, ++offset) {
if (Character.toUpperCase(s.charAt(offset)) != keyword[i]) {
return false;
}
}
return true;
}
return false;
}
}