Skip to content

Commit

Permalink
Merge pull request #3811 from katzyn/misc
Browse files Browse the repository at this point in the history
BTRIM function, octal and binary literals and other changes
  • Loading branch information
katzyn committed Jun 5, 2023
2 parents e424dc2 + b89e453 commit ed4fcb1
Show file tree
Hide file tree
Showing 24 changed files with 370 additions and 94 deletions.
6 changes: 6 additions & 0 deletions h2/src/docsrc/html/changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ <h1>Change Log</h1>

<h2>Next Version (unreleased)</h2>
<ul>
<li>PR #3811: BTRIM function, octal and binary literals and other changes
</li>
<li>Issue #352: In comparison text values are converted to INT even when they should be converted to BIGINT
</li>
<li>PR #3797: MSSQL mode: Discard table hints on plain UPDATE statements
</li>
<li>PR #3791: Formatted cast of datetimes to/from character strings
</li>
<li>Issue #3785: CSVRead: Fails to translate empty Numbers, when cells are quoted
Expand Down
4 changes: 4 additions & 0 deletions h2/src/main/org/h2/bnf/Bnf.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ private void parse(Reader reader) throws SQLException, IOException {
addFixedRule("anything_except_two_dollar_signs", RuleFixed.ANY_EXCEPT_2_DOLLAR);
addFixedRule("anything", RuleFixed.ANY_WORD);
addFixedRule("@hex_start@", RuleFixed.HEX_START);
addFixedRule("@octal_start@", RuleFixed.OCTAL_START);
addFixedRule("@binary_start@", RuleFixed.BINARY_START);
addFixedRule("@concat@", RuleFixed.CONCAT);
addFixedRule("@az_@", RuleFixed.AZ_UNDERSCORE);
addFixedRule("@af@", RuleFixed.AF);
Expand Down Expand Up @@ -309,6 +311,8 @@ private String[] tokenize() {
syntax = StringUtils.replaceAll(syntax, "nnnnnnnnn", "@nanos@");
syntax = StringUtils.replaceAll(syntax, "function", "@func@");
syntax = StringUtils.replaceAll(syntax, "0x", "@hexStart@");
syntax = StringUtils.replaceAll(syntax, "0o", "@octalStart@");
syntax = StringUtils.replaceAll(syntax, "0b", "@binaryStart@");
syntax = StringUtils.replaceAll(syntax, ",...", "@commaDots@");
syntax = StringUtils.replaceAll(syntax, "...", "@dots@");
syntax = StringUtils.replaceAll(syntax, "||", "@concat@");
Expand Down
48 changes: 37 additions & 11 deletions h2/src/main/org/h2/bnf/RuleFixed.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,25 @@
*/
public class RuleFixed implements Rule {

public static final int YMD = 0, HMS = 1, NANOS = 2;
public static final int ANY_EXCEPT_SINGLE_QUOTE = 3;
public static final int ANY_EXCEPT_DOUBLE_QUOTE = 4;
public static final int ANY_UNTIL_EOL = 5;
public static final int ANY_UNTIL_END = 6;
public static final int ANY_WORD = 7;
public static final int ANY_EXCEPT_2_DOLLAR = 8;
public static final int HEX_START = 10, CONCAT = 11;
public static final int AZ_UNDERSCORE = 12, AF = 13, DIGIT = 14;
public static final int OPEN_BRACKET = 15, CLOSE_BRACKET = 16;
public static final int JSON_TEXT = 17;
public static final int YMD = 0;
public static final int HMS = YMD + 1;
public static final int NANOS = HMS + 1;
public static final int ANY_EXCEPT_SINGLE_QUOTE = NANOS + 1;
public static final int ANY_EXCEPT_DOUBLE_QUOTE = ANY_EXCEPT_SINGLE_QUOTE + 1;
public static final int ANY_UNTIL_EOL = ANY_EXCEPT_DOUBLE_QUOTE + 1;
public static final int ANY_UNTIL_END = ANY_UNTIL_EOL + 1;
public static final int ANY_WORD = ANY_UNTIL_END + 1;
public static final int ANY_EXCEPT_2_DOLLAR = ANY_WORD + 1;
public static final int HEX_START = ANY_EXCEPT_2_DOLLAR + 1;
public static final int OCTAL_START = HEX_START + 1;
public static final int BINARY_START = OCTAL_START + 1;
public static final int CONCAT = BINARY_START + 1;
public static final int AZ_UNDERSCORE = CONCAT + 1;
public static final int AF = AZ_UNDERSCORE + 1;
public static final int DIGIT = AF + 1;
public static final int OPEN_BRACKET = DIGIT + 1;
public static final int CLOSE_BRACKET = OPEN_BRACKET + 1;
public static final int JSON_TEXT = CLOSE_BRACKET + 1;

private final int type;

Expand Down Expand Up @@ -133,6 +141,24 @@ public boolean autoComplete(Sentence sentence) {
sentence.add("0x", "0x", Sentence.KEYWORD);
}
break;
case OCTAL_START:
if (s.startsWith("0O") || s.startsWith("0o")) {
s = s.substring(2);
} else if ("0".equals(s)) {
sentence.add("0o", "o", Sentence.KEYWORD);
} else if (s.length() == 0) {
sentence.add("0o", "0o", Sentence.KEYWORD);
}
break;
case BINARY_START:
if (s.startsWith("0B") || s.startsWith("0b")) {
s = s.substring(2);
} else if ("0".equals(s)) {
sentence.add("0b", "b", Sentence.KEYWORD);
} else if (s.length() == 0) {
sentence.add("0b", "0b", Sentence.KEYWORD);
}
break;
case CONCAT:
if (s.equals("|")) {
sentence.add("||", "|", Sentence.KEYWORD);
Expand Down
34 changes: 20 additions & 14 deletions h2/src/main/org/h2/command/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -4067,11 +4067,6 @@ private Expression readCompatibilityFunction(String name) {
// SUBSTRING
case "SUBSTR":
return readSubstringFunction();
// TRIM
case "LTRIM":
return new TrimFunction(readExpression(), readIfArgument(), TrimFunction.LEADING);
case "RTRIM":
return new TrimFunction(readExpression(), readIfArgument(), TrimFunction.TRAILING);
// UPPER
case "UCASE":
return new StringFunction1(readSingleArgument(), StringFunction1.UPPER);
Expand Down Expand Up @@ -4302,6 +4297,15 @@ private Expression readBuiltinFunctionIf(String upperName) {
return new LengthFunction(readIfSingleArgument(), LengthFunction.BIT_LENGTH);
case "TRIM":
return readTrimFunction();
case "LTRIM":
return new TrimFunction(readExpression(), readIfArgument(),
TrimFunction.LEADING | TrimFunction.MULTI_CHARACTER);
case "RTRIM":
return new TrimFunction(readExpression(), readIfArgument(),
TrimFunction.TRAILING | TrimFunction.MULTI_CHARACTER);
case "BTRIM":
return new TrimFunction(readExpression(), readIfArgument(),
TrimFunction.LEADING | TrimFunction.TRAILING | TrimFunction.MULTI_CHARACTER);
case "REGEXP_LIKE":
return readParameters(new RegexpFunction(RegexpFunction.REGEXP_LIKE));
case "REGEXP_REPLACE":
Expand Down Expand Up @@ -4961,22 +4965,24 @@ private ArrayList<Parameter> getUsedParameters(BitSet outerUsedParameters) {

private Expression readTerm() {
Expression r = currentTokenType == IDENTIFIER ? readTermWithIdentifier() : readTermWithoutIdentifier();
if (readIf(OPEN_BRACKET)) {
r = new ArrayElementReference(r, readExpression());
read(CLOSE_BRACKET);
}
if (readIf(COLON_COLON)) {
r = readColonColonAfterTerm(r);
}
for (;;) {
if (readIf(OPEN_BRACKET)) {
r = new ArrayElementReference(r, readExpression());
read(CLOSE_BRACKET);
continue;
}
if (readIf(COLON_COLON)) {
r = readColonColonAfterTerm(r);
continue;
}
TypeInfo ti = readIntervalQualifier();
if (ti != null) {
r = new CastSpecification(r, ti);
continue;
}
int index = tokenIndex;
if (readIf("AT")) {
if (readIf("TIME")) {
read("ZONE");
if (readIf("TIME", "ZONE")) {
r = new TimeZoneOperation(r, readExpression());
continue;
} else if (readIf("LOCAL")) {
Expand Down
46 changes: 43 additions & 3 deletions h2/src/main/org/h2/command/Tokenizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,14 @@ ArrayList<Token> tokenize(String sql, boolean stopOnCloseParen, BitSet parameter
break;
case '0':
if (i < end) {
char c2 = sql.charAt(i + 1);
if (c2 == 'X' || c2 == 'x') {
switch (sql.charAt(i + 1) & 0xffdf) {
case 'B':
i = readIntegerNumber(sql, i, end, i + 2, tokens, "Binary number", 2);
continue loop;
case 'O':
i = readIntegerNumber(sql, i, end, i + 2, tokens, "Octal number", 8);
continue loop;
case 'X':
i = readHexNumber(sql, provider, i, end, i + 2, tokens);
continue loop;
}
Expand Down Expand Up @@ -1182,7 +1188,6 @@ private static int readHexNumber(String sql, CastDataProvider provider, int toke
return finishBigInteger(sql, tokenStart, end, i, start, i <= end && c == 'L', 16, tokens);
}
} while (++i <= end);

boolean bigint = i <= end && c == 'L';
if (bigint) {
i++;
Expand All @@ -1195,6 +1200,41 @@ private static int readHexNumber(String sql, CastDataProvider provider, int toke
}
}

private static int readIntegerNumber(String sql, int tokenStart, int end, int i, ArrayList<Token> tokens,
String name, int radix) {
if (i > end) {
throw DbException.getSyntaxError(sql, tokenStart, name);
}
char maxDigit = (char) (('0' - 1) + radix);
int start = i;
long number = 0;
char c;
do {
c = sql.charAt(i);
if (c >= '0' && c <= maxDigit) {
number = (number * radix) + c - '0';
} else if (i == start) {
throw DbException.getSyntaxError(sql, tokenStart, name);
} else {
break;
}
if (number > Integer.MAX_VALUE) {
while (++i <= end && (c = sql.charAt(i)) >= '0' && c <= maxDigit) {
}
return finishBigInteger(sql, tokenStart, end, i, start, i <= end && c == 'L', radix, tokens);
}
} while (++i <= end);
boolean bigint = i <= end && c == 'L';
if (bigint) {
i++;
}
if (i <= end && Character.isJavaIdentifierPart(sql.codePointAt(i))) {
throw DbException.getSyntaxError(sql, tokenStart, name);
}
tokens.add(bigint ? new Token.BigintToken(start, number) : new Token.IntegerToken(start, (int) number));
return i;
}

private static int readNumeric(String sql, int tokenStart, int end, int i, char c, ArrayList<Token> tokens) {
long number = c - '0';
for (; i <= end; i++) {
Expand Down
4 changes: 2 additions & 2 deletions h2/src/main/org/h2/engine/Database.java
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ public Database(ConnectionInfo ci, String cipher) {
this.databaseURL = ci.getURL();
String s = ci.removeProperty("DATABASE_EVENT_LISTENER", null);
if (s != null) {
setEventListenerClass(StringUtils.trim(s, true, true, "'"));
setEventListenerClass(StringUtils.trim(s, true, true, '\''));
}
s = ci.removeProperty("MODE", null);
if (s != null) {
Expand All @@ -264,7 +264,7 @@ public Database(ConnectionInfo ci, String cipher) {
}
s = ci.getProperty("JAVA_OBJECT_SERIALIZER", null);
if (s != null) {
s = StringUtils.trim(s, true, true, "'");
s = StringUtils.trim(s, true, true, '\'');
javaObjectSerializerName = s;
}
this.allowBuiltinAliasOverride = ci.getProperty("BUILTIN_ALIAS_OVERRIDE", false);
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/engine/SessionRemote.java
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ private void connectServer(ConnectionInfo ci) {
if (autoReconnect) {
String className = ci.getProperty("DATABASE_EVENT_LISTENER");
if (className != null) {
className = StringUtils.trim(className, true, true, "'");
className = StringUtils.trim(className, true, true, '\'');
try {
eventListener = (DatabaseEventListener) JdbcUtils
.loadUserClass(className).getDeclaredConstructor().newInstance();
Expand Down
4 changes: 2 additions & 2 deletions h2/src/main/org/h2/expression/function/StringFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ public final class StringFunction extends FunctionN {
public static final int REPLACE = INSERT + 1;

/**
* LPAD() (non-standard).
* LPAD().
*/
public static final int LPAD = REPLACE + 1;

/**
* RPAD() (non-standard).
* RPAD().
*/
public static final int RPAD = LPAD + 1;

Expand Down
62 changes: 42 additions & 20 deletions h2/src/main/org/h2/expression/function/TrimFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import org.h2.value.ValueVarchar;

/**
* A TRIM function.
* A TRIM, LTRIM, RTRIM, or BTRIM function.
*/
public final class TrimFunction extends Function1_2 {

Expand All @@ -28,6 +28,11 @@ public final class TrimFunction extends Function1_2 {
*/
public static final int TRAILING = 2;

/**
* The multi-character flag.
*/
public static final int MULTI_CHARACTER = 4;

private int flags;

public TrimFunction(Expression from, Expression space, int flags) {
Expand Down Expand Up @@ -57,30 +62,47 @@ public Expression optimize(SessionLocal session) {
@Override
public StringBuilder getUnenclosedSQL(StringBuilder builder, int sqlFlags) {
builder.append(getName()).append('(');
boolean needFrom = false;
switch (flags) {
case LEADING:
builder.append("LEADING ");
needFrom = true;
break;
case TRAILING:
builder.append("TRAILING ");
needFrom = true;
break;
if ((flags & MULTI_CHARACTER) != 0) {
left.getUnenclosedSQL(builder, sqlFlags);
if (right != null) {
right.getUnenclosedSQL(builder.append(", "), sqlFlags);
}
} else {
boolean needFrom = false;
switch (flags) {
case LEADING:
builder.append("LEADING ");
needFrom = true;
break;
case TRAILING:
builder.append("TRAILING ");
needFrom = true;
break;
}
if (right != null) {
right.getUnenclosedSQL(builder, sqlFlags);
needFrom = true;
}
if (needFrom) {
builder.append(" FROM ");
}
left.getUnenclosedSQL(builder, sqlFlags);
}
if (right != null) {
right.getUnenclosedSQL(builder, sqlFlags);
needFrom = true;
}
if (needFrom) {
builder.append(" FROM ");
}
return left.getUnenclosedSQL(builder, sqlFlags).append(')');
return builder.append(')');
}

@Override
public String getName() {
return "TRIM";
switch (flags) {
case LEADING | MULTI_CHARACTER:
return "LTRIM";
case TRAILING | MULTI_CHARACTER:
return "RTRIM";
case LEADING | TRAILING | MULTI_CHARACTER:
return "BTRIM";
default:
return "TRIM";
}
}

}

0 comments on commit ed4fcb1

Please sign in to comment.