blob: 13b9b419f48994f16d723e2dcc0beb08f21b33f2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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 org.apache.geode.cache.query.internal.parse;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.StringTokenizer;
import antlr.Token;
import org.apache.geode.cache.query.QueryInvalidException;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.internal.QCompiler;
public class ASTLiteral extends GemFireAST {
private static final long serialVersionUID = 8374021603235812835L;
public ASTLiteral() {}
public ASTLiteral(Token t) {
super(t);
}
private Object computeValue() throws QueryInvalidException {
switch (getType()) {
case OQLLexerTokenTypes.StringLiteral:
return getString(getText(), '\'');
case OQLLexerTokenTypes.NUM_INT:
return getInt(getText());
case OQLLexerTokenTypes.NUM_DOUBLE:
return getDouble(getText());
case OQLLexerTokenTypes.NUM_FLOAT:
return getFloat(getText());
case OQLLexerTokenTypes.NUM_LONG:
return getLong(getText());
case OQLLexerTokenTypes.LITERAL_nil:
case OQLLexerTokenTypes.LITERAL_null:
return null;
case OQLLexerTokenTypes.LITERAL_undefined:
return QueryService.UNDEFINED;
case OQLLexerTokenTypes.LITERAL_true:
return Boolean.TRUE;
case OQLLexerTokenTypes.LITERAL_false:
return Boolean.FALSE;
case OQLLexerTokenTypes.LITERAL_char:
return getChar(getFirstChild().getText());
case OQLLexerTokenTypes.LITERAL_date:
return getDate(getFirstChild().getText());
case OQLLexerTokenTypes.LITERAL_timestamp:
return getTimestamp(getFirstChild().getText());
case OQLLexerTokenTypes.LITERAL_time:
return getTime(getFirstChild().getText());
default:
throw new Error("unknown literal type: " + getType());
}
}
public Integer getInt(String s) throws QueryInvalidException {
try {
return Integer.valueOf(s);
} catch (NumberFormatException e) {
throw new QueryInvalidException(
String.format("unable to parse integer: %s", s), e);
}
}
public Long getLong(String s) throws QueryInvalidException {
char last = s.charAt(s.length() - 1);
boolean strip = last == 'L' || last == 'l';
if (strip)
s = s.substring(0, s.length() - 1);
try {
return Long.valueOf(s);
} catch (NumberFormatException e) {
throw new QueryInvalidException(
String.format("Unable to parse float %s", s));
}
}
public Float getFloat(String s) throws QueryInvalidException {
char last = s.charAt(s.length() - 1);
boolean strip = last == 'F' || last == 'f';
if (strip)
s = s.substring(0, s.length() - 1);
try {
return new Float(s);
} catch (NumberFormatException e) {
throw new QueryInvalidException(s);
}
}
public Double getDouble(String s) throws QueryInvalidException {
char last = s.charAt(s.length() - 1);
boolean strip = last == 'D' || last == 'd';
if (strip)
s = s.substring(0, s.length() - 1);
try {
return Double.valueOf(s);
} catch (NumberFormatException e) {
throw new QueryInvalidException(
String.format("Unable to parse double %s", s));
}
}
private String getString(String s, char delim) {
// replace embedded double delims with delim
StringBuffer buf = new StringBuffer(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == delim && i < (s.length() - 1) && s.charAt(i + 1) == delim)
i++;
buf.append(c);
}
return buf.toString();
}
@Override
public void compile(QCompiler compiler) throws QueryInvalidException {
Object value = computeValue();
compiler.pushLiteral(value);
}
private Character getChar(String s) {
if (s.length() != 1)
throw new QueryInvalidException(
"Illegal format for CHAR literal. A character literal must have exactly one character");
return new Character(s.charAt(0));
}
private java.sql.Date getDate(String s) {
try {
java.sql.Date date = java.sql.Date.valueOf(s);
// passed valueOf, now verify args are really in range
int firstDash = s.indexOf('-');
int secondDash = s.indexOf('-', firstDash + 1);
int month = Integer.parseInt(s.substring(firstDash + 1, secondDash));
int day = Integer.parseInt(s.substring(secondDash + 1));
if (month < 1 || month > 12)
throw new QueryInvalidException(
"Month must be 1..12 in DATE literal");
if (day < 1 || day > 31)
throw new QueryInvalidException(
"Day must be 1..31 in DATE literal");
return date;
} catch (IllegalArgumentException e) {
throw new QueryInvalidException(
String.format("Illegal format for DATE literal: %s . Expected format is yyyy-mm-dd",
s));
}
}
private java.sql.Time getTime(String s) {
try {
Time time = java.sql.Time.valueOf(s);
// passed valueOf, now verify args are really in range
int firstColon = s.indexOf(':');
int secondColon = s.indexOf(':', firstColon + 1);
int hour = Integer.parseInt(s.substring(0, firstColon));
int minute = Integer.parseInt(s.substring(firstColon + 1, secondColon));
int second = Integer.parseInt(s.substring(secondColon + 1));
if (hour < 0 || hour > 23)
throw new QueryInvalidException(
"Hour must be 0..23 in TIME literal");
if (minute < 0 || minute > 59)
throw new QueryInvalidException(
"Minute must be 0..59 in TIME literal");
if (second < 0 || second > 59)
throw new QueryInvalidException(
"Second must be 0..59 in TIME literal");
return time;
} catch (IllegalArgumentException e) {
throw new QueryInvalidException(
String.format("Illegal format for TIME literal: %s . Expected format is hh:mm:ss",
s));
}
}
private java.sql.Timestamp getTimestamp(String s) {
try {
Timestamp timestamp = java.sql.Timestamp.valueOf(s);
// passed valueOf, now make sure parameters are in range
// first rule out negative numbers by counting the dashes
int count = 0;
int index = -1;
while ((index = s.indexOf('-', index + 1)) >= 0)
count++;
if (count > 2)
throw new QueryInvalidException(
"Negative numbers not allowed in TIMESTAMP literal");
// now just get the numbers, ignoring delimiters
StringTokenizer tokenizer = new StringTokenizer(s, ":-\t\n\r\f ");
// skip year, anything is valid
tokenizer.nextToken();
int month = Integer.parseInt(tokenizer.nextToken());
if (month < 1 || month > 12)
throw new QueryInvalidException(
"Month must be 1..12 in TIMESTAMP literal");
int day = Integer.parseInt(tokenizer.nextToken());
if (day < 1 || day > 31)
throw new QueryInvalidException(
"Day must be 1..31 in TIMESTAMP literal");
int hour = Integer.parseInt(tokenizer.nextToken());
if (hour < 0 || hour > 23)
throw new QueryInvalidException(
"Hour must be 0..23 in TIMESTAMP literal");
int minute = Integer.parseInt(tokenizer.nextToken());
if (minute < 0 || minute > 59)
throw new QueryInvalidException(
"Minute must be 0..59 in TIMESTAMP literal");
String sec_s = tokenizer.nextToken();
int period = sec_s.indexOf('.');
int second;
if (period >= 0)
second = Integer.parseInt(sec_s.substring(0, period));
else
second = Integer.parseInt(sec_s);
if (second < 0 || second > 59)
throw new QueryInvalidException(
"Second must be 0..59 in TIMESTAMP literal");
return timestamp;
} catch (IllegalArgumentException e) {
throw new QueryInvalidException(
String.format(
"Illegal format for TIMESTAMP literal: %s . Expected format is yyyy-mm-dd hh:mm:ss.fffffffff",
s));
}
}
}