Skip to content

Commit

Permalink
支持转义字符
Browse files Browse the repository at this point in the history
  • Loading branch information
jiayuanv127 committed Jul 12, 2017
1 parent 463f913 commit 2f41a14
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 115 deletions.
227 changes: 216 additions & 11 deletions cql/src/main/java/com/huawei/streaming/cql/CQLUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

package com.huawei.streaming.cql;

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -78,17 +82,8 @@ public static String cqlStringLiteralTrim(String str)
{
return null;
}

String s = str;
if (s.startsWith("'") || s.startsWith("\""))
{
s = s.substring(1, s.length());
}
if (s.endsWith("'") || s.endsWith("\""))
{
s = s.substring(0, s.length() - 1);
}
return s;

return unescapeSQLString(str);
}

/**
Expand All @@ -103,4 +98,214 @@ public static ClassLoader getClassLoader()
}
return classLoader;
}

private static final int[] multiplier = new int[] {1000, 100, 10, 1};

/**
* 转义字符处理
* @param b
* @return
*/
public static String unescapeSQLString(String b) {
Character enclosure = null;

// Some of the strings can be passed in as unicode. For example, the
// delimiter can be passed in as \002 - So, we first check if the
// string is a unicode number, else go back to the old behavior
StringBuilder sb = new StringBuilder(b.length());
for (int i = 0; i < b.length(); i++) {

char currentChar = b.charAt(i);
if (enclosure == null) {
if (currentChar == '\'' || currentChar == '\"') {
enclosure = currentChar;
}
// ignore all other chars outside the enclosure
continue;
}

if (enclosure.equals(currentChar)) {
enclosure = null;
continue;
}

if (currentChar == '\\' && (i + 6 < b.length()) && b.charAt(i + 1) == 'u') {
int code = 0;
int base = i + 2;
for (int j = 0; j < 4; j++) {
int digit = Character.digit(b.charAt(j + base), 16);
code += digit * multiplier[j];
}
sb.append((char)code);
i += 5;
continue;
}

if (currentChar == '\\' && (i + 4 < b.length())) {
char i1 = b.charAt(i + 1);
char i2 = b.charAt(i + 2);
char i3 = b.charAt(i + 3);
if ((i1 >= '0' && i1 <= '1') && (i2 >= '0' && i2 <= '7')
&& (i3 >= '0' && i3 <= '7')) {
byte bVal = (byte) ((i3 - '0') + ((i2 - '0') * 8) + ((i1 - '0') * 8 * 8));
byte[] bValArr = new byte[1];
bValArr[0] = bVal;
String tmp = new String(bValArr);
sb.append(tmp);
i += 3;
continue;
}
}

if (currentChar == '\\' && (i + 2 < b.length())) {
char n = b.charAt(i + 1);
switch (n) {
case '0':
sb.append("\0");
break;
case '\'':
sb.append("'");
break;
case '"':
sb.append("\"");
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("\u001A");
break;
case '\\':
sb.append("\\");
break;
// The following 2 lines are exactly what MySQL does TODO: why do we do this?
case '%':
sb.append("\\%");
break;
case '_':
sb.append("\\_");
break;
default:
sb.append(n);
}
i++;
} else {
sb.append(currentChar);
}
}
return sb.toString();
}

public static String escapeSQLString(String b) {
// There's usually nothing to escape so we will be optimistic.
String result = b;
for (int i = 0; i < result.length(); ++i) {
char currentChar = result.charAt(i);
if (currentChar == '\\' && ((i + 1) < result.length())) {
// TODO: do we need to handle the "this is what MySQL does" here?
char nextChar = result.charAt(i + 1);
if (nextChar == '%' || nextChar == '_') {
++i;
continue;
}
}
switch (currentChar) {
case '\0': result = spliceString(result, i, "\\0"); ++i; break;
case '\'': result = spliceString(result, i, "\\'"); ++i; break;
case '\"': result = spliceString(result, i, "\\\""); ++i; break;
case '\b': result = spliceString(result, i, "\\b"); ++i; break;
case '\n': result = spliceString(result, i, "\\n"); ++i; break;
case '\r': result = spliceString(result, i, "\\r"); ++i; break;
case '\t': result = spliceString(result, i, "\\t"); ++i; break;
case '\\': result = spliceString(result, i, "\\\\"); ++i; break;
case '\u001A': result = spliceString(result, i, "\\Z"); ++i; break;
default: {
if (currentChar < ' ') {
String hex = Integer.toHexString(currentChar);
String unicode = "\\u";
for (int j = 4; j > hex.length(); --j) {
unicode += '0';
}
unicode += hex;
result = spliceString(result, i, unicode);
i += (unicode.length() - 1);
}
break; // if not a control character, do nothing
}
}
}

return "'"+result+"'";
}

private static String spliceString(String str, int i, String replacement) {
return spliceString(str, i, 1, replacement);
}

private static String spliceString(String str, int i, int length, String replacement) {
return str.substring(0, i) + replacement + str.substring(i + length);
}

public static String constantToString(Class<?> datatype,Object value) {
if (datatype == null)
{
return "NULL";
}

if (datatype == Integer.class)
{
return value.toString();
}

if (datatype == Long.class)
{
return value.toString() + "L";
}

if (datatype == Float.class)
{
return value.toString() + "F";
}

if (datatype == Double.class)
{
return value.toString() + "D";
}

if (datatype == Date.class)
{
return value.toString() + "DT";
}

if (datatype == Time.class)
{
return value.toString() + "TM";
}

if (datatype == Timestamp.class)
{
return value.toString() + "TS";
}

if (datatype == BigDecimal.class)
{
return value.toString() + "BD";
}

if (datatype == Boolean.class)
{
return value.toString();
}

return CQLUtils.escapeSQLString(value.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@

package com.huawei.streaming.cql.semanticanalyzer.analyzecontext.expressiondesc;

import com.huawei.streaming.cql.CQLUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.huawei.streaming.cql.executor.expressioncreater.ConstExpressionCreator;
import com.huawei.streaming.cql.executor.operatorinfocreater.ExpressionCreatorAnnotation;
import com.huawei.streaming.exception.StreamingException;
import com.huawei.streaming.util.StreamingDataType;

/**
* 常量表达式的描述
Expand Down Expand Up @@ -62,29 +61,7 @@ public ConstExpressionDesc(Object constValue, Class< ? > type)
@Override
public String toString()
{

//对应常量值为null的场景
if (constValue == null)
{
return null;
}

StreamingDataType dataType = null;

try
{
dataType = StreamingDataType.getStreamingDataType(type);
}
catch (StreamingException e)
{
LOG.warn("Ignore an StreamingExpression.");
return "'" + constValue + "'";
}

String constStringValue = constValue.toString();
String postfix = getConstPostfix(dataType);
//没有时间类型的常量,统一按照字符串标准进行处理
return postfix == null ? "'" + constValue + "'" : constStringValue + postfix;
return CQLUtils.constantToString(type,constValue);
}

public Object getConstValue()
Expand All @@ -107,25 +84,4 @@ public void setType(Class< ? > type)
this.type = type;
}

private String getConstPostfix(StreamingDataType dataType)
{
//各种事件类型没有常量,统一按照字符串来处理
//int和boolean没有后缀
switch (dataType)
{
case INT:
case BOOLEAN:
return "";
case LONG:
return "L";
case FLOAT:
return "F";
case DOUBLE:
return "D";
case DECIMAL:
return "BD";
default:
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@

package com.huawei.streaming.cql.semanticanalyzer.parser.context;

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;

import com.huawei.streaming.cql.CQLUtils;
import com.huawei.streaming.cql.exception.SemanticAnalyzerException;
import com.huawei.streaming.cql.semanticanalyzer.analyzecontext.expressiondesc.ConstExpressionDesc;
import com.huawei.streaming.cql.semanticanalyzer.analyzecontext.expressiondesc.ExpressionDescribe;
Expand Down Expand Up @@ -76,60 +73,7 @@ public void setValue(Object value)
@Override
public String toString()
{
if (datatype == null)
{
return "NULL";
}

if (datatype == Integer.class)
{
return value.toString();
}

if (datatype == Long.class)
{
return value.toString() + "L";
}

if (datatype == Float.class)
{
return value.toString() + "F";
}

if (datatype == Double.class)
{
return value.toString() + "D";
}

if (datatype == Date.class)
{
return value.toString() + "DT";
}

if (datatype == Time.class)
{
return value.toString() + "TM";
}

if (datatype == Timestamp.class)
{
return value.toString() + "TS";
}

if (datatype == BigDecimal.class)
{
return value.toString() + "BD";
}

if (datatype == Boolean.class)
{
return value.toString();
}
if (value.toString().contains("\""))
{
return "'" + value.toString() + "'";
}
return "\"" + value.toString() + "\"";
return CQLUtils.constantToString(datatype,value);
}

/**
Expand Down

0 comments on commit 2f41a14

Please sign in to comment.