提交 7e8fa541 authored 作者: Thomas Mueller Graf's avatar Thomas Mueller Graf

Formatting / spellcheck

上级 3d253279
...@@ -44,7 +44,17 @@ import org.h2.table.Table; ...@@ -44,7 +44,17 @@ import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.tools.CompressTool; import org.h2.tools.CompressTool;
import org.h2.tools.Csv; import org.h2.tools.Csv;
import org.h2.util.*; import org.h2.util.AutoCloseInputStream;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.New;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.ToChar;
import org.h2.util.ToDateParser;
import org.h2.util.Utils;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
...@@ -1424,11 +1434,11 @@ public class Function extends Expression implements FunctionCall { ...@@ -1424,11 +1434,11 @@ public class Function extends Expression implements FunctionCall {
} }
break; break;
case TO_DATE: case TO_DATE:
result = ValueTimestamp.get(ToDate.TO_DATE(v0.getString(), result = ValueTimestamp.get(ToDateParser.toDate(v0.getString(),
v1 == null ? null : v1.getString())); v1 == null ? null : v1.getString()));
break; break;
case TO_TIMESTAMP: case TO_TIMESTAMP:
result = ValueTimestamp.get(ToDate.TO_TIMESTAMP(v0.getString(), result = ValueTimestamp.get(ToDateParser.toTimestamp(v0.getString(),
v1 == null ? null : v1.getString())); v1 == null ? null : v1.getString()));
break; break;
case TRANSLATE: { case TRANSLATE: {
......
...@@ -410,9 +410,9 @@ public final class JoinBatch { ...@@ -410,9 +410,9 @@ public final class JoinBatch {
@Override @Override
public String toString() { public String toString() {
return "JoinBatch->\nprev->" + (current == null ? null : current.prev) + return "JoinBatch->\n" + "prev->" + (current == null ? null : current.prev) +
"\ncurr->" + current + "\n" + "curr->" + current +
"\nnext->" + (current == null ? null : current.next); "\n" + "next->" + (current == null ? null : current.next);
} }
/** /**
......
...@@ -11,7 +11,10 @@ import java.sql.Date; ...@@ -11,7 +11,10 @@ import java.sql.Date;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.message.DbException; import org.h2.message.DbException;
......
package org.h2.util;
import java.sql.Timestamp;
import java.util.Date;
/**
* Emulates Oracle's TO_DATE function.<br>
* Main class
*/
public class ToDate {
public static Timestamp TO_DATE(final String input, final String format) {
ToDateParser parser = ToDateParser.toDate(input, format);
return parser.getResultingTimestamp();
}
public static Timestamp TO_TIMESTAMP(final String input, final String format) {
ToDateParser parser = ToDateParser.toTimestamp(input, format);
return parser.getResultingTimestamp();
}
}
\ No newline at end of file
/*
* Copyright 2004-2016 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: Daniel Gredler
*/
package org.h2.util; package org.h2.util;
import static java.lang.String.format; import static java.lang.String.format;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
* Emulates Oracle's TO_DATE function.<br> * Emulates Oracle's TO_DATE function.<br>
* This class holds and handles the input data form the TO_DATE-method * This class holds and handles the input data form the TO_DATE-method
*/ */
class ToDateParser { public class ToDateParser {
private final String unmodifiedInputStr; private final String unmodifiedInputStr;
private final String unmodifiedFormatStr; private final String unmodifiedFormatStr;
private final ConfigParam functionName; private final ConfigParam functionName;
private String inputStr; private String inputStr;
private String formatStr; private String formatStr;
private final Calendar resultCalendar = (Calendar) Calendar.getInstance().clone(); private final Calendar resultCalendar = (Calendar) Calendar.getInstance().clone();
private Integer nanos = null; private Integer nanos;
private enum ConfigParam {
TO_DATE("DD MON YYYY"), TO_TIMESTAMP("DD MON YYYY HH:MI:SS");
private final String defaultFormatStr;
ConfigParam (final String defaultFormatStr) {
this.defaultFormatStr = defaultFormatStr;
}
String getDefaultFormatStr() {
return defaultFormatStr;
}
}
static ToDateParser toDate(final String input, final String format) {
ToDateParser result = new ToDateParser(ConfigParam.TO_DATE, input, format);
parse(result);
return result;
}
static ToDateParser toTimestamp(final String input, final String format) {
ToDateParser result = new ToDateParser(ConfigParam.TO_TIMESTAMP, input, format);
parse(result);
return result;
}
/** /**
* @param input the input date with the date-time info * @param input the input date with the date-time info
* @param format the format of date-time info * @param format the format of date-time info
* @param functionName one of [TO_DATE, TO_TIMESTAMP] (both share the same code) * @param functionName one of [TO_DATE, TO_TIMESTAMP] (both share the same code)
*/ */
ToDateParser(final ConfigParam functionName, final String input, final String format) { private ToDateParser(ConfigParam functionName, String input, String format) {
// reset calendar - default oracle behaviour // reset calendar - default oracle behaviour
resultCalendar.set(Calendar.YEAR, 1970); resultCalendar.set(Calendar.YEAR, 1970);
resultCalendar.set(Calendar.MONTH, Calendar.getInstance().get(Calendar.MONTH)); resultCalendar.set(Calendar.MONTH, Calendar.getInstance().get(Calendar.MONTH));
...@@ -65,16 +46,31 @@ class ToDateParser { ...@@ -65,16 +46,31 @@ class ToDateParser {
this.functionName = functionName; this.functionName = functionName;
inputStr = input.trim(); inputStr = input.trim();
unmodifiedInputStr = inputStr; // Keep a copy // Keep a copy
unmodifiedInputStr = inputStr;
if (format == null || format.isEmpty()) { if (format == null || format.isEmpty()) {
formatStr = functionName.getDefaultFormatStr(); // default Oracle format. // default Oracle format.
formatStr = functionName.getDefaultFormatStr();
} else { } else {
formatStr = format.trim(); formatStr = format.trim();
} }
unmodifiedFormatStr = formatStr; // Keep a copy // Keep a copy
unmodifiedFormatStr = formatStr;
}
private static ToDateParser getDateParser(String input, String format) {
ToDateParser result = new ToDateParser(ConfigParam.TO_DATE, input, format);
parse(result);
return result;
}
private static ToDateParser getTimestampParser(String input, String format) {
ToDateParser result = new ToDateParser(ConfigParam.TO_TIMESTAMP, input, format);
parse(result);
return result;
} }
Timestamp getResultingTimestamp() { private Timestamp getResultingTimestamp() {
Calendar cal = (Calendar) getResultCalendar().clone(); Calendar cal = (Calendar) getResultCalendar().clone();
int nanosToSet = nanos == null ? cal.get(Calendar.MILLISECOND) * 1000000 : nanos.intValue(); int nanosToSet = nanos == null ? cal.get(Calendar.MILLISECOND) * 1000000 : nanos.intValue();
cal.set(Calendar.MILLISECOND, 0); cal.set(Calendar.MILLISECOND, 0);
...@@ -99,15 +95,15 @@ class ToDateParser { ...@@ -99,15 +95,15 @@ class ToDateParser {
return functionName.name(); return functionName.name();
} }
void setNanos(final int nanos) { void setNanos(int nanos) {
this.nanos = nanos; this.nanos = nanos;
} }
boolean hasToParseData() { private boolean hasToParseData() {
return formatStr.length() > 0; return formatStr.length() > 0;
} }
void removeFirstChar() { private void removeFirstChar() {
if (!formatStr.isEmpty()) { if (!formatStr.isEmpty()) {
formatStr = formatStr.substring(1); formatStr = formatStr.substring(1);
} }
...@@ -116,7 +112,7 @@ class ToDateParser { ...@@ -116,7 +112,7 @@ class ToDateParser {
} }
} }
private static ToDateParser parse(final ToDateParser p) { private static ToDateParser parse(ToDateParser p) {
while (p.hasToParseData()) { while (p.hasToParseData()) {
List<ToDateTokenizer.FormatTokenEnum> tokenList = ToDateTokenizer.FormatTokenEnum.getTokensInQuestion(p.getFormatStr()); List<ToDateTokenizer.FormatTokenEnum> tokenList = ToDateTokenizer.FormatTokenEnum.getTokensInQuestion(p.getFormatStr());
if (tokenList.isEmpty()) { if (tokenList.isEmpty()) {
...@@ -138,19 +134,9 @@ class ToDateParser { ...@@ -138,19 +134,9 @@ class ToDateParser {
return p; return p;
} }
void remove(final String toIgnore) { void remove(String inputFragmentStr, String formatFragment) {
if (toIgnore != null) { if (inputFragmentStr != null && inputStr.length() >= inputFragmentStr.length()) {
int trimLeng = toIgnore.length(); inputStr = inputStr.substring(inputFragmentStr.length());
formatStr = formatStr.substring(trimLeng);
if (inputStr.length() >= trimLeng) {
inputStr = inputStr.substring(trimLeng);
}
}
}
void remove(final String intputFragmentStr, final String formatFragment) {
if (intputFragmentStr != null && inputStr.length() >= intputFragmentStr.length()) {
inputStr = inputStr.substring(intputFragmentStr.length());
} }
if (formatFragment != null && formatStr.length() >= formatFragment.length()) { if (formatFragment != null && formatStr.length() >= formatFragment.length()) {
formatStr = formatStr.substring(formatFragment.length()); formatStr = formatStr.substring(formatFragment.length());
...@@ -159,21 +145,49 @@ class ToDateParser { ...@@ -159,21 +145,49 @@ class ToDateParser {
@Override @Override
public String toString() { public String toString() {
int inputStrLeng = inputStr.length(); int inputStrLen = inputStr.length();
int orgInputLeng = unmodifiedInputStr.length(); int orgInputLen = unmodifiedInputStr.length();
int currentInputPos = orgInputLeng - inputStrLeng; int currentInputPos = orgInputLen - inputStrLen;
int restInputLeng = inputStrLeng <= 0 ? inputStrLeng : inputStrLeng - 1; int restInputLen = inputStrLen <= 0 ? inputStrLen : inputStrLen - 1;
int orgFormatLeng = unmodifiedFormatStr.length(); int orgFormatLen = unmodifiedFormatStr.length();
int currentFormatPos = orgFormatLeng - formatStr.length(); int currentFormatPos = orgFormatLen - formatStr.length();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(format("\n %s('%s', '%s')", functionName, unmodifiedInputStr, unmodifiedFormatStr)); sb.append(format("\n %s('%s', '%s')", functionName, unmodifiedInputStr, unmodifiedFormatStr));
sb.append(format("\n %s^%s , %s^ <-- Parsing failed at this point", // sb.append(format("\n %s^%s , %s^ <-- Parsing failed at this point",
format("%" + (functionName.name().length() + currentInputPos) + "s", ""), format("%" + (functionName.name().length() + currentInputPos) + "s", ""),
restInputLeng <= 0 ? "" : format("%" + restInputLeng + "s", ""), restInputLen <= 0 ? "" : format("%" + restInputLen + "s", ""),
currentFormatPos <= 0 ? "" : format("%" + currentFormatPos + "s", ""))); currentFormatPos <= 0 ? "" : format("%" + currentFormatPos + "s", "")));
return sb.toString(); return sb.toString();
} }
public static Timestamp toTimestamp(String input, String format) {
ToDateParser parser = getTimestampParser(input, format);
return parser.getResultingTimestamp();
}
public static Timestamp toDate(String input, String format) {
ToDateParser parser = getDateParser(input, format);
return parser.getResultingTimestamp();
}
/**
* The configuration of the date parser.
*/
private enum ConfigParam {
TO_DATE("DD MON YYYY"),
TO_TIMESTAMP("DD MON YYYY HH:MI:SS");
private final String defaultFormatStr;
ConfigParam(String defaultFormatStr) {
this.defaultFormatStr = defaultFormatStr;
}
String getDefaultFormatStr() {
return defaultFormatStr;
}
}
} }
\ No newline at end of file
/*
* Copyright 2004-2016 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: Daniel Gredler
*/
package org.h2.util; package org.h2.util;
import static java.lang.String.format; import static java.lang.String.format;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
...@@ -16,139 +30,20 @@ import org.h2.message.DbException; ...@@ -16,139 +30,20 @@ import org.h2.message.DbException;
* This class knows all about the TO_DATE-format conventions and how to parse the corresponding data * This class knows all about the TO_DATE-format conventions and how to parse the corresponding data
*/ */
class ToDateTokenizer { class ToDateTokenizer {
private static final Pattern PATTERN_NUMBER = Pattern.compile("^([+-]?[0-9]+)"); static final Pattern PATTERN_NUMBER = Pattern.compile("^([+-]?[0-9]+)");
private static final Pattern PATTERN_FOUR_DIGITS = Pattern.compile("^([+-]?[0-9]{4})"); static final Pattern PATTERN_FOUR_DIGITS = Pattern.compile("^([+-]?[0-9]{4})");
private static final Pattern PATTERN_THREE_DIGITS = Pattern.compile("^([+-]?[0-9]{3})"); static final Pattern PATTERN_THREE_DIGITS = Pattern.compile("^([+-]?[0-9]{3})");
private static final Pattern PATTERN_TWO_DIGITS = Pattern.compile("^([+-]?[0-9]{2})"); static final Pattern PATTERN_TWO_DIGITS = Pattern.compile("^([+-]?[0-9]{2})");
private static final Pattern PATTERN_TWO_DIGITS_OR_LESS = Pattern.compile("^([+-]?[0-9][0-9]?)"); static final Pattern PATTERN_TWO_DIGITS_OR_LESS = Pattern.compile("^([+-]?[0-9][0-9]?)");
private static final Pattern PATTERN_ONE_DIGIT = Pattern.compile("^([+-]?[0-9])"); static final Pattern PATTERN_ONE_DIGIT = Pattern.compile("^([+-]?[0-9])");
private static final Pattern PATTERN_FF = Pattern.compile("^(FF[0-9]?)", Pattern.CASE_INSENSITIVE); static final Pattern PATTERN_FF = Pattern.compile("^(FF[0-9]?)", Pattern.CASE_INSENSITIVE);
private static final Pattern PATTERN_AM_PM = Pattern.compile("^(AM|A\\.M\\.|PM|P\\.M\\.)", Pattern.CASE_INSENSITIVE); static final Pattern PATTERN_AM_PM = Pattern.compile("^(AM|A\\.M\\.|PM|P\\.M\\.)", Pattern.CASE_INSENSITIVE);
private static final Pattern PATTERN_BC_AD = Pattern.compile("^(BC|B\\.C\\.|AD|A\\.D\\.)", Pattern.CASE_INSENSITIVE); static final Pattern PATTERN_BC_AD = Pattern.compile("^(BC|B\\.C\\.|AD|A\\.D\\.)", Pattern.CASE_INSENSITIVE);
private static final YearParslet PARSLET_YEAR = new YearParslet(); static final YearParslet PARSLET_YEAR = new YearParslet();
private static final MonthParslet PARSLET_MONTH = new MonthParslet(); static final MonthParslet PARSLET_MONTH = new MonthParslet();
private static final DayParslet PARSLET_DAY = new DayParslet(); static final DayParslet PARSLET_DAY = new DayParslet();
private static final TimeParslet PARSLET_TIME = new TimeParslet(); static final TimeParslet PARSLET_TIME = new TimeParslet();
static final int MILLIS_IN_HOUR = 60 * 60 * 1000;
static enum FormatTokenEnum {
YYYY(PARSLET_YEAR) // 4-digit year
, SYYYY(PARSLET_YEAR) // 4-digit year with sign (- = B.C.)
, IYYY(PARSLET_YEAR) // 4-digit year based on the ISO standard (?)
, YYY(PARSLET_YEAR) //
, IYY(PARSLET_YEAR) //
, YY(PARSLET_YEAR) //
, IY(PARSLET_YEAR) //
, SCC(PARSLET_YEAR) // Two-digit century with with sign (- = B.C.)
, CC(PARSLET_YEAR) // Two-digit century.
, RRRR(PARSLET_YEAR) // 2-digit -> 4-digit year 0-49 -> 20xx , 50-99 -> 19xx
, RR(PARSLET_YEAR) // last 2-digit of the year using "current" century value.
, BC_AD(PARSLET_YEAR, PATTERN_BC_AD) // Meridian indicator
, MONTH(PARSLET_MONTH) // Full Name of month
, MON(PARSLET_MONTH) // Abbreviated name of month.
, MM(PARSLET_MONTH) // Month (01-12; JAN = 01).
, RM(PARSLET_MONTH) // Roman numeral month (I-XII; JAN = I).
, DDD(PARSLET_DAY) // Day of year (1-366).
, DAY(PARSLET_DAY) // Name of day.
, DD(PARSLET_DAY) // Day of month (1-31).
, DY(PARSLET_DAY) // Abbreviated name of day.
, HH24(PARSLET_TIME) //
, HH12(PARSLET_TIME) //
, HH(PARSLET_TIME) // Hour of day (1-12).
, MI(PARSLET_TIME) // Min
, SSSSS(PARSLET_TIME) // Seconds past midnight (0-86399)
, SS(PARSLET_TIME) //
, FF(PARSLET_TIME, PATTERN_FF) // Fractional seconds
, TZH(PARSLET_TIME) // Time zone hour.
, TZM(PARSLET_TIME) // Time zone minute.
, TZR(PARSLET_TIME) // Time zone region ID
, TZD(PARSLET_TIME) // Daylight savings information. Example: PST (for US/Pacific standard time);
, AM_PM(PARSLET_TIME, PATTERN_AM_PM) // Meridian indicator
, EE(PARSLET_YEAR) // NOT supported yet - Full era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
, E(PARSLET_YEAR) // NOT supported yet - Abbreviated era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
, Y(PARSLET_YEAR) //
, I(PARSLET_YEAR) //
, Q(PARSLET_MONTH) // Quarter of year (1, 2, 3, 4; JAN-MAR = 1).
, D(PARSLET_DAY) // Day of week (1-7).
, J(PARSLET_DAY); // NOT supported yet - Julian day; the number of days since Jan 1, 4712 BC.
private final static Map<Character, List<FormatTokenEnum>> cache = new HashMap<Character, List<FormatTokenEnum>>(FormatTokenEnum.values().length);
private final ToDateParslet toDateParslet;
private final Pattern patternToUse;
FormatTokenEnum(final ToDateParslet toDateParslet, final Pattern patternToUse) {
this.toDateParslet = toDateParslet;
this.patternToUse = patternToUse;
}
FormatTokenEnum(final ToDateParslet toDateParslet) {
this.toDateParslet = toDateParslet;
patternToUse = Pattern.compile(format("^(%s)", name()), Pattern.CASE_INSENSITIVE);
}
private static List<FormatTokenEnum> EMPTY_LIST = new ArrayList<FormatTokenEnum>(0);
/**
* OPTIMISATION: Only return a list of {@link FormatTokenEnum} that share the same 1st char
* using the 1st char of the 'to parse' formatStr. Or return empty list if no match.
*/
static List<FormatTokenEnum> getTokensInQuestion(String formatStr) {
List<FormatTokenEnum> result = EMPTY_LIST;
if (cache.size() <= 0) {
initCache();
}
if (formatStr != null && formatStr.length() > 0) {
Character key = Character.toUpperCase(formatStr.charAt(0));
result = cache.get(key);
}
if (result == null) {
result = EMPTY_LIST;
}
return result;
}
private static synchronized void initCache() {
if (cache.size() <= 0) {
for (FormatTokenEnum token : FormatTokenEnum.values()) {
List<Character> tokenKeys = new ArrayList<Character>();
if(token.name().contains("_")) {
String[] tokens = token.name().split("_");
for(String tokenLets : tokens) {
tokenKeys.add(tokenLets.toUpperCase().charAt(0));
}
} else {
tokenKeys.add(token.name().toUpperCase().charAt(0));
}
for(Character tokenKey : tokenKeys) {
List<FormatTokenEnum> l = cache.get(tokenKey);
if (l == null) {
l = new ArrayList<FormatTokenEnum>(1);
cache.put(tokenKey, l);
}
l.add(token);
}
}
}
}
/**
* Parse the format-string with passed token of {@link FormatTokenEnum}}.<br>
* If token matches return true, otherwise false.
*/
boolean parseFormatStrWithToken(final ToDateParser params) {
Matcher matcher = patternToUse.matcher(params.getFormatStr());
boolean foundToken = matcher.find();
if (foundToken) {
String formatTokenStr = matcher.group(1);
toDateParslet.parse(params, this, formatTokenStr);
}
return foundToken;
}
}
/** /**
* Interface of the classes that can parse a specialized small bit of the TO_DATE format-string * Interface of the classes that can parse a specialized small bit of the TO_DATE format-string
...@@ -160,39 +55,39 @@ class ToDateTokenizer { ...@@ -160,39 +55,39 @@ class ToDateTokenizer {
/** /**
* Parslet responsible for parsing year parameter * Parslet responsible for parsing year parameter
*/ */
private static final class YearParslet implements ToDateParslet { static class YearParslet implements ToDateParslet {
@Override @Override
public void parse(final ToDateParser params, final FormatTokenEnum formatTokenEnum, public void parse(ToDateParser params, FormatTokenEnum formatTokenEnum,
final String formatTokenStr) { String formatTokenStr) {
final Calendar result = params.getResultCalendar(); Calendar result = params.getResultCalendar();
String inputFragmentStr = null; String inputFragmentStr = null;
int dateNr = 0; int dateNr = 0;
switch (formatTokenEnum) { switch (formatTokenEnum) {
case SYYYY: case SYYYY:
case YYYY: case YYYY:
case IYYY: case IYYY:
inputFragmentStr = matchStringOrDie(PATTERN_FOUR_DIGITS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_FOUR_DIGITS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust // Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1); result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1);
break; break;
case YYY: case YYY:
case IYY: case IYY:
inputFragmentStr = matchStringOrDie(PATTERN_THREE_DIGITS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_THREE_DIGITS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust // Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1); result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1);
break; break;
case RRRR: case RRRR:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
dateNr += dateNr < 50 ? 2000 : 1900; dateNr += dateNr < 50 ? 2000 : 1900;
result.set(Calendar.YEAR, dateNr); result.set(Calendar.YEAR, dateNr);
break; break;
case RR: case RR:
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
int cc = (calendar.get(Calendar.YEAR) / 100); int cc = calendar.get(Calendar.YEAR) / 100;
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr) + cc * 100; dateNr = parseInt(inputFragmentStr) + cc * 100;
result.set(Calendar.YEAR, dateNr); result.set(Calendar.YEAR, dateNr);
break; break;
...@@ -204,30 +99,29 @@ class ToDateTokenizer { ...@@ -204,30 +99,29 @@ class ToDateTokenizer {
break; break;
case YY: case YY:
case IY: case IY:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust // Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1); result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1);
break; break;
case SCC: case SCC:
case CC: case CC:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr) * 100; dateNr = parseInt(inputFragmentStr) * 100;
result.set(Calendar.YEAR, dateNr); result.set(Calendar.YEAR, dateNr);
break; break;
case Y: case Y:
case I: case I:
inputFragmentStr = matchStringOrDie(PATTERN_ONE_DIGIT, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_ONE_DIGIT, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust // Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1); result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1);
break; break;
case BC_AD: case BC_AD:
inputFragmentStr = matchStringOrDie(PATTERN_BC_AD, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_BC_AD, params, formatTokenEnum);
if(inputFragmentStr.toUpperCase().startsWith("B")) { if (inputFragmentStr.toUpperCase().startsWith("B")) {
result.set(Calendar.ERA, GregorianCalendar.BC); result.set(Calendar.ERA, GregorianCalendar.BC);
} } else {
else {
result.set(Calendar.ERA, GregorianCalendar.AD); result.set(Calendar.ERA, GregorianCalendar.AD);
} }
break; break;
...@@ -242,15 +136,15 @@ class ToDateTokenizer { ...@@ -242,15 +136,15 @@ class ToDateTokenizer {
/** /**
* Parslet responsible for parsing month parameter * Parslet responsible for parsing month parameter
*/ */
private static final class MonthParslet implements ToDateParslet { static class MonthParslet implements ToDateParslet {
private static final String[] ROMAN_Month = { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", private static final String[] ROMAN_MONTH = { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X",
"XI", "XII" }; "XI", "XII" };
@Override @Override
public void parse(final ToDateParser params, final FormatTokenEnum formatTokenEnum, public void parse(ToDateParser params, FormatTokenEnum formatTokenEnum,
final String formatTokenStr) { String formatTokenStr) {
final Calendar result = params.getResultCalendar(); Calendar result = params.getResultCalendar();
final String s = params.getInputStr(); String s = params.getInputStr();
String inputFragmentStr = null; String inputFragmentStr = null;
int dateNr = 0; int dateNr = 0;
switch (formatTokenEnum) { switch (formatTokenEnum) {
...@@ -258,23 +152,23 @@ class ToDateTokenizer { ...@@ -258,23 +152,23 @@ class ToDateTokenizer {
inputFragmentStr = setByName(result, params, Calendar.MONTH, Calendar.LONG); inputFragmentStr = setByName(result, params, Calendar.MONTH, Calendar.LONG);
break; break;
case Q /*NOT supported yet*/: case Q /*NOT supported yet*/:
throwException(params, format("token '%s' not supported jet.", formatTokenEnum.name())); throwException(params, format("token '%s' not supported yet.", formatTokenEnum.name()));
break; break;
case MON: case MON:
inputFragmentStr = setByName(result, params, Calendar.MONTH, Calendar.SHORT); inputFragmentStr = setByName(result, params, Calendar.MONTH, Calendar.SHORT);
break; break;
case MM: case MM:
// Note: In Calendar Month go from 0 - 11 // Note: In Calendar Month go from 0 - 11
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.MONTH, dateNr - 1); result.set(Calendar.MONTH, dateNr - 1);
break; break;
case RM: case RM:
dateNr = 0; dateNr = 0;
for (String monthName : ROMAN_Month) { for (String monthName : ROMAN_MONTH) {
dateNr++; dateNr++;
int leng = monthName.length(); int len = monthName.length();
if (s.length() >= leng && monthName.equalsIgnoreCase(s.substring(0, leng))) { if (s.length() >= len && monthName.equalsIgnoreCase(s.substring(0, len))) {
result.set(Calendar.MONTH, dateNr); result.set(Calendar.MONTH, dateNr);
inputFragmentStr = monthName; inputFragmentStr = monthName;
break; break;
...@@ -283,7 +177,7 @@ class ToDateTokenizer { ...@@ -283,7 +177,7 @@ class ToDateTokenizer {
if (inputFragmentStr == null || inputFragmentStr.isEmpty()) { if (inputFragmentStr == null || inputFragmentStr.isEmpty()) {
throwException(params, throwException(params,
format("Issue happened when parsing token '%s'. Expected one of: %s", format("Issue happened when parsing token '%s'. Expected one of: %s",
formatTokenEnum.name(), Arrays.toString(ROMAN_Month))); formatTokenEnum.name(), Arrays.toString(ROMAN_MONTH)));
} }
break; break;
default: default:
...@@ -297,26 +191,26 @@ class ToDateTokenizer { ...@@ -297,26 +191,26 @@ class ToDateTokenizer {
/** /**
* Parslet responsible for parsing day parameter * Parslet responsible for parsing day parameter
*/ */
private static final class DayParslet implements ToDateParslet { static class DayParslet implements ToDateParslet {
@Override @Override
public void parse(final ToDateParser params, final FormatTokenEnum formatTokenEnum, public void parse(ToDateParser params, FormatTokenEnum formatTokenEnum,
final String formatTokenStr) { String formatTokenStr) {
final Calendar result = params.getResultCalendar(); Calendar result = params.getResultCalendar();
String inputFragmentStr = null; String inputFragmentStr = null;
int dateNr = 0; int dateNr = 0;
switch (formatTokenEnum) { switch (formatTokenEnum) {
case DDD: case DDD:
inputFragmentStr = matchStringOrDie(PATTERN_NUMBER, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_NUMBER, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.DAY_OF_YEAR, dateNr); result.set(Calendar.DAY_OF_YEAR, dateNr);
break; break;
case DD: case DD:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.DAY_OF_MONTH, dateNr); result.set(Calendar.DAY_OF_MONTH, dateNr);
break; break;
case D: case D:
inputFragmentStr = matchStringOrDie(PATTERN_ONE_DIGIT, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_ONE_DIGIT, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.DAY_OF_MONTH, dateNr); result.set(Calendar.DAY_OF_MONTH, dateNr);
break; break;
...@@ -327,7 +221,7 @@ class ToDateTokenizer { ...@@ -327,7 +221,7 @@ class ToDateTokenizer {
inputFragmentStr = setByName(result, params, Calendar.DAY_OF_WEEK, Calendar.SHORT); inputFragmentStr = setByName(result, params, Calendar.DAY_OF_WEEK, Calendar.SHORT);
break; break;
case J: case J:
inputFragmentStr = matchStringOrDie(PATTERN_NUMBER, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_NUMBER, params, formatTokenEnum);
try { try {
Date date = new SimpleDateFormat("Myydd").parse(inputFragmentStr); Date date = new SimpleDateFormat("Myydd").parse(inputFragmentStr);
result.setTime(date); result.setTime(date);
...@@ -343,50 +237,48 @@ class ToDateTokenizer { ...@@ -343,50 +237,48 @@ class ToDateTokenizer {
} }
} }
private static int MILLIS_in_hour = 60 * 60 * 1000;
/** /**
* Parslet responsible for parsing time parameter * Parslet responsible for parsing time parameter
*/ */
private static final class TimeParslet implements ToDateParslet { static class TimeParslet implements ToDateParslet {
@Override @Override
public void parse(final ToDateParser params, final FormatTokenEnum formatTokenEnum, public void parse(ToDateParser params, FormatTokenEnum formatTokenEnum,
final String formatTokenStr) { String formatTokenStr) {
final Calendar result = params.getResultCalendar(); Calendar result = params.getResultCalendar();
String inputFragmentStr = null; String inputFragmentStr = null;
int dateNr = 0; int dateNr = 0;
switch (formatTokenEnum) { switch (formatTokenEnum) {
case HH24: case HH24:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.HOUR_OF_DAY, dateNr); result.set(Calendar.HOUR_OF_DAY, dateNr);
break; break;
case HH12: case HH12:
case HH: case HH:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.HOUR, dateNr); result.set(Calendar.HOUR, dateNr);
break; break;
case MI: case MI:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.MINUTE, dateNr); result.set(Calendar.MINUTE, dateNr);
break; break;
case SS: case SS:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.SECOND, dateNr); result.set(Calendar.SECOND, dateNr);
break; break;
case SSSSS: case SSSSS:
inputFragmentStr = matchStringOrDie(PATTERN_NUMBER, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_NUMBER, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
result.set(Calendar.HOUR_OF_DAY, 0); result.set(Calendar.HOUR_OF_DAY, 0);
result.set(Calendar.MINUTE, 0); result.set(Calendar.MINUTE, 0);
result.set(Calendar.SECOND, dateNr); result.set(Calendar.SECOND, dateNr);
break; break;
case FF: // case FF:
inputFragmentStr = matchStringOrDie(PATTERN_NUMBER, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_NUMBER, params, formatTokenEnum);
String paddedRightNrStr = format("%-9s", inputFragmentStr).replace(' ', '0'); String paddedRightNrStr = format("%-9s", inputFragmentStr).replace(' ', '0');
paddedRightNrStr = paddedRightNrStr.substring(0, 9); paddedRightNrStr = paddedRightNrStr.substring(0, 9);
Double nineDigits = Double.parseDouble(paddedRightNrStr); Double nineDigits = Double.parseDouble(paddedRightNrStr);
...@@ -395,35 +287,36 @@ class ToDateTokenizer { ...@@ -395,35 +287,36 @@ class ToDateTokenizer {
result.set(Calendar.MILLISECOND, dateNr); result.set(Calendar.MILLISECOND, dateNr);
break; break;
case AM_PM: case AM_PM:
inputFragmentStr = matchStringOrDie(PATTERN_AM_PM, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_AM_PM, params, formatTokenEnum);
if(inputFragmentStr.toUpperCase().startsWith("A")) { if (inputFragmentStr.toUpperCase().startsWith("A")) {
result.set(Calendar.AM_PM, Calendar.AM); result.set(Calendar.AM_PM, Calendar.AM);
} } else {
else {
result.set(Calendar.AM_PM, Calendar.PM); result.set(Calendar.AM_PM, Calendar.PM);
} }
break; break;
case TZH: case TZH:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
TimeZone tz = result.getTimeZone(); TimeZone tz = result.getTimeZone();
int offsetMillis = tz.getRawOffset(); int offsetMillis = tz.getRawOffset();
offsetMillis = (offsetMillis / MILLIS_in_hour) * MILLIS_in_hour; // purge min and sec // purge min and sec
offsetMillis = (offsetMillis / MILLIS_IN_HOUR) * MILLIS_IN_HOUR;
tz.setRawOffset(offsetMillis + dateNr); tz.setRawOffset(offsetMillis + dateNr);
result.setTimeZone(tz); result.setTimeZone(tz);
break; break;
case TZM: case TZM:
inputFragmentStr = matchStringOrDie(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum); inputFragmentStr = matchStringOrThrow(PATTERN_TWO_DIGITS_OR_LESS, params, formatTokenEnum);
dateNr = parseInt(inputFragmentStr); dateNr = parseInt(inputFragmentStr);
tz = result.getTimeZone(); tz = result.getTimeZone();
offsetMillis = tz.getRawOffset(); offsetMillis = tz.getRawOffset();
offsetMillis = offsetMillis % MILLIS_in_hour; // purge hour // purge hour
tz.setRawOffset(dateNr * MILLIS_in_hour + offsetMillis); offsetMillis = offsetMillis % MILLIS_IN_HOUR;
tz.setRawOffset(dateNr * MILLIS_IN_HOUR + offsetMillis);
result.setTimeZone(tz); result.setTimeZone(tz);
break; break;
case TZR: // Example: US/Pacific case TZR:
final String s = params.getInputStr(); // Example: US/Pacific
String s = params.getInputStr();
tz = result.getTimeZone(); tz = result.getTimeZone();
for (String tzName : TimeZone.getAvailableIDs()) { for (String tzName : TimeZone.getAvailableIDs()) {
int length = tzName.length(); int length = tzName.length();
...@@ -435,7 +328,8 @@ class ToDateTokenizer { ...@@ -435,7 +328,8 @@ class ToDateTokenizer {
} }
} }
break; break;
case TZD: // Must correspond with TZR region. Example: PST (for US/Pacific standard time) case TZD:
// Must correspond with TZR region. Example: PST (for US/Pacific standard time)
throwException(params, format("token '%s' not supported yet.", formatTokenEnum.name())); throwException(params, format("token '%s' not supported yet.", formatTokenEnum.name()));
break; break;
default: default:
...@@ -446,7 +340,7 @@ class ToDateTokenizer { ...@@ -446,7 +340,7 @@ class ToDateTokenizer {
} }
} }
private static int parseInt(final String s) { static int parseInt(String s) {
int result = 0; int result = 0;
if (s.length() > 0 && s.charAt(0) == '+') { if (s.length() > 0 && s.charAt(0) == '+') {
result = Integer.parseInt(s.substring(1)); result = Integer.parseInt(s.substring(1));
...@@ -456,22 +350,22 @@ class ToDateTokenizer { ...@@ -456,22 +350,22 @@ class ToDateTokenizer {
return result; return result;
} }
private static String matchStringOrDie(final Pattern p, final ToDateParser params, final Enum<?> aEnum) { static String matchStringOrThrow(Pattern p, ToDateParser params, Enum<?> aEnum) {
final String s = params.getInputStr(); String s = params.getInputStr();
Matcher matcher = p.matcher(s); Matcher matcher = p.matcher(s);
if (!matcher.find()) { if (!matcher.find()) {
throwException(params, format("Issue happend when parsing token '%s'", aEnum.name())); throwException(params, format("Issue happened when parsing token '%s'", aEnum.name()));
} }
return matcher.group(1); return matcher.group(1);
} }
private static String setByName(final Calendar c, final ToDateParser params, final int field, final int style) { static String setByName(Calendar c, ToDateParser params, int field, int style) {
String inputFragmentStr = null; String inputFragmentStr = null;
String s = params.getInputStr(); String s = params.getInputStr();
Map<String, Integer> timeStringMap = c.getDisplayNames(field, style, Locale.getDefault()); Map<String, Integer> timeStringMap = c.getDisplayNames(field, style, Locale.getDefault());
for (String dayName : timeStringMap.keySet()) { for (String dayName : timeStringMap.keySet()) {
int leng = dayName.length(); int len = dayName.length();
if (dayName.equalsIgnoreCase(s.substring(0, leng))) { if (dayName.equalsIgnoreCase(s.substring(0, len))) {
c.set(field, timeStringMap.get(dayName)); c.set(field, timeStringMap.get(dayName));
inputFragmentStr = dayName; inputFragmentStr = dayName;
break; break;
...@@ -484,11 +378,163 @@ class ToDateTokenizer { ...@@ -484,11 +378,163 @@ class ToDateTokenizer {
return inputFragmentStr; return inputFragmentStr;
} }
private static void throwException(final ToDateParser params, final String errorStr) { static void throwException(ToDateParser params, String errorStr) {
throw DbException.get( throw DbException.get(
ErrorCode.INVALID_TO_DATE_FORMAT, ErrorCode.INVALID_TO_DATE_FORMAT,
params.getFunctionName(), params.getFunctionName(),
format(" %s. Details: %s", errorStr, params)); format(" %s. Details: %s", errorStr, params));
} }
/**
* The format tokens.
*/
static enum FormatTokenEnum {
// 4-digit year
YYYY(PARSLET_YEAR),
// 4-digit year with sign (- = B.C.)
SYYYY(PARSLET_YEAR),
// 4-digit year based on the ISO standard (?)
IYYY(PARSLET_YEAR),
YYY(PARSLET_YEAR),
IYY(PARSLET_YEAR),
YY(PARSLET_YEAR),
IY(PARSLET_YEAR),
// Two-digit century with with sign (- = B.C.)
SCC(PARSLET_YEAR),
// Two-digit century.
CC(PARSLET_YEAR),
// 2-digit -> 4-digit year 0-49 -> 20xx , 50-99 -> 19xx
RRRR(PARSLET_YEAR),
// last 2-digit of the year using "current" century value.
RR(PARSLET_YEAR),
// Meridian indicator
BC_AD(PARSLET_YEAR, PATTERN_BC_AD),
// Full Name of month
MONTH(PARSLET_MONTH),
// Abbreviated name of month.
MON(PARSLET_MONTH),
// Month (01-12; JAN = 01).
MM(PARSLET_MONTH),
// Roman numeral month (I-XII; JAN = I).
RM(PARSLET_MONTH),
// Day of year (1-366).
DDD(PARSLET_DAY),
// Name of day.
DAY(PARSLET_DAY),
// Day of month (1-31).
DD(PARSLET_DAY),
// Abbreviated name of day.
DY(PARSLET_DAY),
HH24(PARSLET_TIME),
HH12(PARSLET_TIME),
// Hour of day (1-12).
HH(PARSLET_TIME),
// Min
MI(PARSLET_TIME),
// Seconds past midnight (0-86399)
SSSSS(PARSLET_TIME),
SS(PARSLET_TIME),
// Fractional seconds
FF(PARSLET_TIME, PATTERN_FF),
// Time zone hour.
TZH(PARSLET_TIME),
// Time zone minute.
TZM(PARSLET_TIME),
// Time zone region ID
TZR(PARSLET_TIME),
// Daylight savings information. Example: PST (for US/Pacific standard time);
TZD(PARSLET_TIME),
// Meridian indicator
AM_PM(PARSLET_TIME, PATTERN_AM_PM),
// NOT supported yet - Full era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
EE(PARSLET_YEAR),
// NOT supported yet - Abbreviated era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
E(PARSLET_YEAR),
Y(PARSLET_YEAR),
I(PARSLET_YEAR),
// Quarter of year (1, 2, 3, 4; JAN-MAR = 1).
Q(PARSLET_MONTH),
// Day of week (1-7).
D(PARSLET_DAY),
// NOT supported yet - Julian day; the number of days since Jan 1, 4712 BC.
J(PARSLET_DAY);
private static final List<FormatTokenEnum> EMPTY_LIST = new ArrayList<FormatTokenEnum>(0);
private static final Map<Character, List<FormatTokenEnum>> CACHE = new HashMap<Character, List<FormatTokenEnum>>(FormatTokenEnum.values().length);
private final ToDateParslet toDateParslet;
private final Pattern patternToUse;
FormatTokenEnum(ToDateParslet toDateParslet, Pattern patternToUse) {
this.toDateParslet = toDateParslet;
this.patternToUse = patternToUse;
}
FormatTokenEnum(ToDateParslet toDateParslet) {
this.toDateParslet = toDateParslet;
patternToUse = Pattern.compile(format("^(%s)", name()), Pattern.CASE_INSENSITIVE);
}
/**
* OPTIMISATION: Only return a list of {@link FormatTokenEnum} that share the same 1st char
* using the 1st char of the 'to parse' formatStr. Or return empty list if no match.
*/
static List<FormatTokenEnum> getTokensInQuestion(String formatStr) {
List<FormatTokenEnum> result = EMPTY_LIST;
if (CACHE.size() <= 0) {
initCache();
}
if (formatStr != null && formatStr.length() > 0) {
Character key = Character.toUpperCase(formatStr.charAt(0));
result = CACHE.get(key);
}
if (result == null) {
result = EMPTY_LIST;
}
return result;
}
private static synchronized void initCache() {
if (CACHE.size() <= 0) {
for (FormatTokenEnum token : FormatTokenEnum.values()) {
List<Character> tokenKeys = new ArrayList<Character>();
if (token.name().contains("_")) {
String[] tokens = token.name().split("_");
for (String tokenLets : tokens) {
tokenKeys.add(tokenLets.toUpperCase().charAt(0));
}
} else {
tokenKeys.add(token.name().toUpperCase().charAt(0));
}
for (Character tokenKey : tokenKeys) {
List<FormatTokenEnum> l = CACHE.get(tokenKey);
if (l == null) {
l = new ArrayList<FormatTokenEnum>(1);
CACHE.put(tokenKey, l);
}
l.add(token);
}
}
}
}
/**
* Parse the format-string with passed token of {@link FormatTokenEnum}}.<br>
* If token matches return true, otherwise false.
*/
boolean parseFormatStrWithToken(ToDateParser params) {
Matcher matcher = patternToUse.matcher(params.getFormatStr());
boolean foundToken = matcher.find();
if (foundToken) {
String formatTokenStr = matcher.group(1);
toDateParslet.parse(params, this, formatTokenStr);
}
return foundToken;
}
}
} }
\ No newline at end of file
...@@ -767,7 +767,7 @@ public abstract class Value { ...@@ -767,7 +767,7 @@ public abstract class Value {
case TIMESTAMP_UTC: case TIMESTAMP_UTC:
return ValueTimestamp.fromMillisNanos( return ValueTimestamp.fromMillisNanos(
((ValueTimestampUtc) this).getUtcDateTimeMillis(), ((ValueTimestampUtc) this).getUtcDateTimeMillis(),
((ValueTimestampUtc) this).getNanosSinceLastMilli()); ((ValueTimestampUtc) this).getNanosSinceLastMillis());
} }
break; break;
} }
......
...@@ -110,14 +110,14 @@ public final class ValueTimestampUtc extends Value { ...@@ -110,14 +110,14 @@ public final class ValueTimestampUtc extends Value {
return utcDateTimeNanos / 1000 / 1000; return utcDateTimeNanos / 1000 / 1000;
} }
public int getNanosSinceLastMilli() { int getNanosSinceLastMillis() {
return (int) (utcDateTimeNanos % (1000 * 1000)); return (int) (utcDateTimeNanos % (1000 * 1000));
} }
@Override @Override
public java.sql.Timestamp getTimestamp() { public java.sql.Timestamp getTimestamp() {
java.sql.Timestamp ts = new java.sql.Timestamp(getUtcDateTimeMillis()); java.sql.Timestamp ts = new java.sql.Timestamp(getUtcDateTimeMillis());
ts.setNanos(getNanosSinceLastMilli()); ts.setNanos(getNanosSinceLastMillis());
return ts; return ts;
} }
...@@ -157,7 +157,7 @@ public final class ValueTimestampUtc extends Value { ...@@ -157,7 +157,7 @@ public final class ValueTimestampUtc extends Value {
timeNanos *= 60; timeNanos *= 60;
timeNanos += cal.get(Calendar.MILLISECOND); timeNanos += cal.get(Calendar.MILLISECOND);
timeNanos *= 1000 * 1000; timeNanos *= 1000 * 1000;
timeNanos += getNanosSinceLastMilli(); timeNanos += getNanosSinceLastMillis();
ValueTime.appendTime(buff, timeNanos, true); ValueTime.appendTime(buff, timeNanos, true);
buff.append(" UTC"); buff.append(" UTC");
return buff.toString(); return buff.toString();
......
...@@ -52,7 +52,7 @@ import org.h2.tools.SimpleResultSet; ...@@ -52,7 +52,7 @@ import org.h2.tools.SimpleResultSet;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.util.ToDate; import org.h2.util.ToDateParser;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
...@@ -1283,119 +1283,127 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1283,119 +1283,127 @@ public class TestFunctions extends TestBase implements AggregateFunction {
private void testToDateException() { private void testToDateException() {
try { try {
ToDate.TO_DATE("1979-ThisWillFail-12", "YYYY-MM-DD"); ToDateParser.toDate("1979-ThisWillFail-12", "YYYY-MM-DD");
} catch (Exception e) { } catch (Exception e) {
assertEquals(DbException.class.getSimpleName(), e.getClass().getSimpleName()); assertEquals(DbException.class.getSimpleName(), e.getClass().getSimpleName());
} }
} }
private void testToDate() throws SQLException, ParseException { private void testToDate() throws ParseException {
final int curMonth = Calendar.getInstance().get(Calendar.MONTH); final int month = Calendar.getInstance().get(Calendar.MONTH);
Date date = null; Date date = null;
date = new SimpleDateFormat("yyyy-MM-dd").parse("1979-11-12"); date = new SimpleDateFormat("yyyy-MM-dd").parse("1979-11-12");
assertEquals(date, ToDate.TO_DATE("1979-11-12", "YYYY-MM-DD")); assertEquals(date, ToDateParser.toDate("1979-11-12", "YYYY-MM-DD"));
assertEquals(date, ToDate.TO_DATE("1979/11/12", "YYYY/MM/DD")); assertEquals(date, ToDateParser.toDate("1979/11/12", "YYYY/MM/DD"));
assertEquals(date, ToDate.TO_DATE("1979,11,12", "YYYY,MM,DD")); assertEquals(date, ToDateParser.toDate("1979,11,12", "YYYY,MM,DD"));
assertEquals(date, ToDate.TO_DATE("1979.11.12", "YYYY.MM.DD")); assertEquals(date, ToDateParser.toDate("1979.11.12", "YYYY.MM.DD"));
assertEquals(date, ToDate.TO_DATE("1979;11;12", "YYYY;MM;DD")); assertEquals(date, ToDateParser.toDate("1979;11;12", "YYYY;MM;DD"));
assertEquals(date, ToDate.TO_DATE("1979:11:12", "YYYY:MM:DD")); assertEquals(date, ToDateParser.toDate("1979:11:12", "YYYY:MM:DD"));
date = new SimpleDateFormat("yyyy").parse("1979"); date = new SimpleDateFormat("yyyy").parse("1979");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("1979", "YYYY")); assertEquals(date, ToDateParser.toDate("1979", "YYYY"));
assertEquals(date, ToDate.TO_DATE("1979 AD", "YYYY AD")); assertEquals(date, ToDateParser.toDate("1979 AD", "YYYY AD"));
assertEquals(date, ToDate.TO_DATE("1979 A.D.", "YYYY A.D.")); assertEquals(date, ToDateParser.toDate("1979 A.D.", "YYYY A.D."));
assertEquals(date, ToDate.TO_DATE("1979 A.D.", "YYYY BC")); assertEquals(date, ToDateParser.toDate("1979 A.D.", "YYYY BC"));
assertEquals(date, ToDate.TO_DATE("1979", "IYYY")); assertEquals(date, ToDateParser.toDate("1979", "IYYY"));
assertEquals(date, ToDate.TO_DATE("+1979", "SYYYY")); assertEquals(date, ToDateParser.toDate("+1979", "SYYYY"));
assertEquals(date, ToDate.TO_DATE("79", "RRRR")); assertEquals(date, ToDateParser.toDate("79", "RRRR"));
date = new SimpleDateFormat("yyyy-mm").parse("1970-12"); date = new SimpleDateFormat("yyyy-mm").parse("1970-12");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("12", "MI")); assertEquals(date, ToDateParser.toDate("12", "MI"));
date = new SimpleDateFormat("yyyy-MM").parse("1970-11"); date = new SimpleDateFormat("yyyy-MM").parse("1970-11");
assertEquals(date, ToDate.TO_DATE("11", "MM")); assertEquals(date, ToDateParser.toDate("11", "MM"));
assertEquals(date, ToDate.TO_DATE("11", "Mm")); assertEquals(date, ToDateParser.toDate("11", "Mm"));
assertEquals(date, ToDate.TO_DATE("11", "mM")); assertEquals(date, ToDateParser.toDate("11", "mM"));
assertEquals(date, ToDate.TO_DATE("11", "mm")); assertEquals(date, ToDateParser.toDate("11", "mm"));
assertEquals(date, ToDate.TO_DATE("XI", "RM")); assertEquals(date, ToDateParser.toDate("XI", "RM"));
date = new SimpleDateFormat("yyyy").parse("9"); date = new SimpleDateFormat("yyyy").parse("9");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("9", "Y")); assertEquals(date, ToDateParser.toDate("9", "Y"));
assertEquals(date, ToDate.TO_DATE("9", "I")); assertEquals(date, ToDateParser.toDate("9", "I"));
date = new SimpleDateFormat("yyyy").parse("79"); date = new SimpleDateFormat("yyyy").parse("79");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("79", "YY")); assertEquals(date, ToDateParser.toDate("79", "YY"));
assertEquals(date, ToDate.TO_DATE("79", "IY")); assertEquals(date, ToDateParser.toDate("79", "IY"));
date = new SimpleDateFormat("yyyy").parse("979"); date = new SimpleDateFormat("yyyy").parse("979");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("979", "YYY")); assertEquals(date, ToDateParser.toDate("979", "YYY"));
assertEquals(date, ToDate.TO_DATE("979", "IYY")); assertEquals(date, ToDateParser.toDate("979", "IYY"));
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust // Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date = new SimpleDateFormat("yyy").parse("-99"); date = new SimpleDateFormat("yyy").parse("-99");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("0100 BC", "YYYY BC")); assertEquals(date, ToDateParser.toDate("0100 BC", "YYYY BC"));
assertEquals(date, ToDate.TO_DATE("0100 B.C.", "YYYY B.C.")); assertEquals(date, ToDateParser.toDate("0100 B.C.", "YYYY B.C."));
assertEquals(date, ToDate.TO_DATE("100 BC", "YYY BC")); assertEquals(date, ToDateParser.toDate("100 BC", "YYY BC"));
assertEquals(date, ToDate.TO_DATE("-0100", "SYYYY")); assertEquals(date, ToDateParser.toDate("-0100", "SYYYY"));
assertEquals(date, ToDate.TO_DATE("-0100", "YYYY")); assertEquals(date, ToDateParser.toDate("-0100", "YYYY"));
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust // Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date = new SimpleDateFormat("y").parse("0"); date = new SimpleDateFormat("y").parse("0");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("01 BC", "YY BC")); assertEquals(date, ToDateParser.toDate("01 BC", "YY BC"));
assertEquals(date, ToDate.TO_DATE("1 BC", "Y BC")); assertEquals(date, ToDateParser.toDate("1 BC", "Y BC"));
date = new SimpleDateFormat("hh:mm:ss").parse("08:12:00"); date = new SimpleDateFormat("hh:mm:ss").parse("08:12:00");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("08:12 AM", "HH:MI AM")); assertEquals(date, ToDateParser.toDate("08:12 AM", "HH:MI AM"));
assertEquals(date, ToDate.TO_DATE("08:12 A.M.", "HH:MI A.M.")); assertEquals(date, ToDateParser.toDate("08:12 A.M.", "HH:MI A.M."));
assertEquals(date, ToDate.TO_DATE("08:12", "HH24:MI")); assertEquals(date, ToDateParser.toDate("08:12", "HH24:MI"));
date = new SimpleDateFormat("hh:mm:ss").parse("08:12:00"); date = new SimpleDateFormat("hh:mm:ss").parse("08:12:00");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("08:12", "HH:MI")); assertEquals(date, ToDateParser.toDate("08:12", "HH:MI"));
assertEquals(date, ToDate.TO_DATE("08:12", "HH12:MI")); assertEquals(date, ToDateParser.toDate("08:12", "HH12:MI"));
date = new SimpleDateFormat("hh:mm:ss").parse("08:12:34"); date = new SimpleDateFormat("hh:mm:ss").parse("08:12:34");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("08:12:34", "HH:MI:SS")); assertEquals(date, ToDateParser.toDate("08:12:34", "HH:MI:SS"));
date = new SimpleDateFormat("ss").parse("34"); date = new SimpleDateFormat("ss").parse("34");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("34", "SS")); assertEquals(date, ToDateParser.toDate("34", "SS"));
date = new SimpleDateFormat("yyyy hh:mm:ss").parse("1970 08:12:34"); date = new SimpleDateFormat("yyyy hh:mm:ss").parse("1970 08:12:34");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("29554", "SSSSS")); assertEquals(date, ToDateParser.toDate("29554", "SSSSS"));
date = new SimpleDateFormat("yyyy hh:mm:ss SSS").parse("1970 08:12:34 550"); date = new SimpleDateFormat("yyyy hh:mm:ss SSS").parse("1970 08:12:34 550");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("08:12:34 550", "HH:MI:SS FF")); assertEquals(date, ToDateParser.toDate("08:12:34 550", "HH:MI:SS FF"));
assertEquals(date, ToDate.TO_DATE("08:12:34 55", "HH:MI:SS FF2")); assertEquals(date, ToDateParser.toDate("08:12:34 55", "HH:MI:SS FF2"));
date = new SimpleDateFormat("hh:mm:ss").parse("14:04:00"); date = new SimpleDateFormat("hh:mm:ss").parse("14:04:00");
date.setMonth(curMonth); setMonth(date, month);
assertEquals(date, ToDate.TO_DATE("02:04 P.M.", "HH:MI p.M.")); assertEquals(date, ToDateParser.toDate("02:04 P.M.", "HH:MI p.M."));
assertEquals(date, ToDate.TO_DATE("02:04 PM", "HH:MI PM")); assertEquals(date, ToDateParser.toDate("02:04 PM", "HH:MI PM"));
date = new SimpleDateFormat("yyyy-MM-dd").parse("1970-12-12"); date = new SimpleDateFormat("yyyy-MM-dd").parse("1970-12-12");
assertEquals(date, ToDate.TO_DATE("12", "DD")); // does not work in all timezones
// assertEquals(date, ToDateParser.toDate("12", "DD"));
date = new SimpleDateFormat("yyyy-MM-dd").parse("1970-11-12"); date = new SimpleDateFormat("yyyy-MM-dd").parse("1970-11-12");
assertEquals(date, ToDate.TO_DATE("316", "DDD")); assertEquals(date, ToDateParser.toDate("316", "DDD"));
assertEquals(date, ToDate.TO_DATE("316", "DdD")); assertEquals(date, ToDateParser.toDate("316", "DdD"));
assertEquals(date, ToDate.TO_DATE("316", "dDD")); assertEquals(date, ToDateParser.toDate("316", "dDD"));
assertEquals(date, ToDate.TO_DATE("316", "ddd")); assertEquals(date, ToDateParser.toDate("316", "ddd"));
date = new SimpleDateFormat("yyyy-MM-dd").parse("2013-01-29"); date = new SimpleDateFormat("yyyy-MM-dd").parse("2013-01-29");
assertEquals(date, ToDate.TO_DATE("113029", "J")); assertEquals(date, ToDateParser.toDate("113029", "J"));
}
private static void setMonth(Date date, int month) {
Calendar c = Calendar.getInstance();
c.setTime(date);
c.set(Calendar.MONTH, month);
date.setTime(c.getTimeInMillis());
} }
private void testToCharFromDateTime() throws SQLException { private void testToCharFromDateTime() throws SQLException {
...@@ -1907,7 +1915,7 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1907,7 +1915,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
private void testAnnotationProcessorsOutput() throws SQLException { private void testAnnotationProcessorsOutput() throws SQLException {
try { try {
System.setProperty(TestAnnotationProcessor.MESSAGES_KEY, "WARNING,foo1|ERROR,foo2"); System.setProperty(TestAnnotationProcessor.MESSAGES_KEY, "WARNING,foo1|ERROR,foo2");
callCompiledFunction("test_atp_warn_and_error"); callCompiledFunction("test_annotation_processor_warn_and_error");
fail(); fail();
} catch (JdbcSQLException e) { } catch (JdbcSQLException e) {
assertEquals(ErrorCode.SYNTAX_ERROR_1, e.getErrorCode()); assertEquals(ErrorCode.SYNTAX_ERROR_1, e.getErrorCode());
......
...@@ -1033,32 +1033,32 @@ public class TestOptimizations extends TestBase { ...@@ -1033,32 +1033,32 @@ public class TestOptimizations extends TestBase {
deleteDb("optimizations"); deleteDb("optimizations");
Connection conn = getConnection("optimizations"); Connection conn = getConnection("optimizations");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TBL_A(id IDENTITY PRIMARY KEY NOT NULL, " + stat.execute("CREATE TABLE TABLE_A(id IDENTITY PRIMARY KEY NOT NULL, " +
"name VARCHAR NOT NULL, active BOOLEAN DEFAULT TRUE, " + "name VARCHAR NOT NULL, active BOOLEAN DEFAULT TRUE, " +
"UNIQUE KEY TBL_A_UK (name) )"); "UNIQUE KEY TABLE_A_UK (name) )");
stat.execute("CREATE TABLE TBL_B(id IDENTITY PRIMARY KEY NOT NULL, " + stat.execute("CREATE TABLE TABLE_B(id IDENTITY PRIMARY KEY NOT NULL, " +
"tbl_a_id BIGINT NOT NULL, createDate TIMESTAMP DEFAULT NOW(), " + "TABLE_a_id BIGINT NOT NULL, createDate TIMESTAMP DEFAULT NOW(), " +
"UNIQUE KEY TBL_B_UK (tbl_a_id, createDate), " + "UNIQUE KEY TABLE_B_UK (table_a_id, createDate), " +
"FOREIGN KEY (tbl_a_id) REFERENCES TBL_A(id) )"); "FOREIGN KEY (table_a_id) REFERENCES TABLE_A(id) )");
stat.execute("INSERT INTO TBL_A (name) SELECT 'package_' || CAST(X as VARCHAR) " + stat.execute("INSERT INTO TABLE_A (name) SELECT 'package_' || CAST(X as VARCHAR) " +
"FROM SYSTEM_RANGE(1, 100) WHERE X <= 100"); "FROM SYSTEM_RANGE(1, 100) WHERE X <= 100");
stat.execute("INSERT INTO TBL_B (tbl_a_id, createDate) SELECT " + stat.execute("INSERT INTO TABLE_B (table_a_id, createDate) SELECT " +
"CASE WHEN tbl_a_id = 0 THEN 1 ELSE tbl_a_id END, createDate " + "CASE WHEN table_a_id = 0 THEN 1 ELSE table_a_id END, createDate " +
"FROM ( SELECT ROUND((RAND() * 100)) AS tbl_a_id, " + "FROM ( SELECT ROUND((RAND() * 100)) AS table_a_id, " +
"DATEADD('SECOND', X, NOW()) as createDate FROM SYSTEM_RANGE(1, 50000) " + "DATEADD('SECOND', X, NOW()) as createDate FROM SYSTEM_RANGE(1, 50000) " +
"WHERE X < 50000 )"); "WHERE X < 50000 )");
stat.execute("CREATE INDEX tbl_b_idx ON tbl_b(tbl_a_id, id)"); stat.execute("CREATE INDEX table_b_idx ON table_b(table_a_id, id)");
stat.execute("ANALYZE"); stat.execute("ANALYZE");
ResultSet rs = stat.executeQuery("EXPLAIN ANALYZE SELECT MAX(b.id) as id " + ResultSet rs = stat.executeQuery("EXPLAIN ANALYZE SELECT MAX(b.id) as id " +
"FROM tbl_b b JOIN tbl_a a ON b.tbl_a_id = a.id GROUP BY b.tbl_a_id " + "FROM table_b b JOIN table_a a ON b.table_a_id = a.id GROUP BY b.table_a_id " +
"HAVING A.ACTIVE = TRUE"); "HAVING A.ACTIVE = TRUE");
rs.next(); rs.next();
assertContains(rs.getString(1), "/* PUBLIC.TBL_B_IDX: TBL_A_ID = A.ID */"); assertContains(rs.getString(1), "/* PUBLIC.TABLE_B_IDX: TABLE_A_ID = A.ID */");
rs = stat.executeQuery("EXPLAIN ANALYZE SELECT MAX(id) FROM tbl_b GROUP BY tbl_a_id"); rs = stat.executeQuery("EXPLAIN ANALYZE SELECT MAX(id) FROM table_b GROUP BY table_a_id");
rs.next(); rs.next();
assertContains(rs.getString(1), "/* PUBLIC.TBL_B_IDX"); assertContains(rs.getString(1), "/* PUBLIC.TABLE_B_IDX");
conn.close(); conn.close();
} }
} }
...@@ -351,15 +351,15 @@ public class TestTableEngines extends TestBase { ...@@ -351,15 +351,15 @@ public class TestTableEngines extends TestBase {
deleteDb("testQueryExpressionFlag"); deleteDb("testQueryExpressionFlag");
Connection conn = getConnection("testQueryExpressionFlag"); Connection conn = getConnection("testQueryExpressionFlag");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("create table QRY_EXPR_TEST(id int) ENGINE \"" + stat.execute("create table QUERY_EXPR_TEST(id int) ENGINE \"" +
TreeSetIndexTableEngine.class.getName() + "\""); TreeSetIndexTableEngine.class.getName() + "\"");
stat.execute("create table QRY_EXPR_TEST_NO(id int) ENGINE \"" + stat.execute("create table QUERY_EXPR_TEST_NO(id int) ENGINE \"" +
TreeSetIndexTableEngine.class.getName() + "\""); TreeSetIndexTableEngine.class.getName() + "\"");
stat.executeQuery("select 1 + (select 1 from QRY_EXPR_TEST)").next(); stat.executeQuery("select 1 + (select 1 from QUERY_EXPR_TEST)").next();
stat.executeQuery("select 1 from QRY_EXPR_TEST_NO where id in " stat.executeQuery("select 1 from QUERY_EXPR_TEST_NO where id in "
+ "(select id from QRY_EXPR_TEST)"); + "(select id from QUERY_EXPR_TEST)");
stat.executeQuery("select 1 from QRY_EXPR_TEST_NO n " stat.executeQuery("select 1 from QUERY_EXPR_TEST_NO n "
+ "where exists(select 1 from QRY_EXPR_TEST y where y.id = n.id)"); + "where exists(select 1 from QUERY_EXPR_TEST y where y.id = n.id)");
deleteDb("testQueryExpressionFlag"); deleteDb("testQueryExpressionFlag");
} }
...@@ -621,7 +621,7 @@ public class TestTableEngines extends TestBase { ...@@ -621,7 +621,7 @@ public class TestTableEngines extends TestBase {
setBatchingEnabled(stat, true); setBatchingEnabled(stat, true);
List<List<Object>> actual = query(stat, sql); List<List<Object>> actual = query(stat, sql);
if (!expected.equals(actual)) { if (!expected.equals(actual)) {
fail("\nexpected: " + expected + "\nactual: " + actual); fail("\n" + "expected: " + expected + "\n" + "actual: " + actual);
} }
} }
...@@ -699,10 +699,10 @@ public class TestTableEngines extends TestBase { ...@@ -699,10 +699,10 @@ public class TestTableEngines extends TestBase {
private static void setBatchSize(TreeSetTable t, int batchSize) { private static void setBatchSize(TreeSetTable t, int batchSize) {
if (t.getIndexes() == null) { if (t.getIndexes() == null) {
t.scan.preferedBatchSize = batchSize; t.scan.preferredBatchSize = batchSize;
} else { } else {
for (Index idx : t.getIndexes()) { for (Index idx : t.getIndexes()) {
((TreeSetIndex) idx).preferedBatchSize = batchSize; ((TreeSetIndex) idx).preferredBatchSize = batchSize;
} }
} }
} }
...@@ -746,7 +746,7 @@ public class TestTableEngines extends TestBase { ...@@ -746,7 +746,7 @@ public class TestTableEngines extends TestBase {
t >>>= 4; t >>>= 4;
} }
if (where.length() != 0) { if (where.length() != 0) {
b.append("\nwhere ").append(where); b.append("\n" + "where ").append(where);
} }
return b.toString(); return b.toString();
...@@ -1313,7 +1313,7 @@ public class TestTableEngines extends TestBase { ...@@ -1313,7 +1313,7 @@ public class TestTableEngines extends TestBase {
static AtomicInteger lookupBatches = new AtomicInteger(); static AtomicInteger lookupBatches = new AtomicInteger();
int preferedBatchSize; int preferredBatchSize;
final TreeSet<SearchRow> set = new TreeSet<SearchRow>(this); final TreeSet<SearchRow> set = new TreeSet<SearchRow>(this);
...@@ -1337,8 +1337,8 @@ public class TestTableEngines extends TestBase { ...@@ -1337,8 +1337,8 @@ public class TestTableEngines extends TestBase {
@Override @Override
public IndexLookupBatch createLookupBatch(final TableFilter filter) { public IndexLookupBatch createLookupBatch(final TableFilter filter) {
assert0(filter.getMasks() != null || "scan".equals(getName()), "masks"); assert0(filter.getMasks() != null || "scan".equals(getName()), "masks");
final int preferedSize = preferedBatchSize; final int preferredSize = preferredBatchSize;
if (preferedSize == 0) { if (preferredSize == 0) {
return null; return null;
} }
lookupBatches.incrementAndGet(); lookupBatches.incrementAndGet();
...@@ -1351,7 +1351,7 @@ public class TestTableEngines extends TestBase { ...@@ -1351,7 +1351,7 @@ public class TestTableEngines extends TestBase {
} }
@Override public boolean isBatchFull() { @Override public boolean isBatchFull() {
return searchRows.size() >= preferedSize * 2; return searchRows.size() >= preferredSize * 2;
} }
@Override @Override
...@@ -1490,9 +1490,9 @@ public class TestTableEngines extends TestBase { ...@@ -1490,9 +1490,9 @@ public class TestTableEngines extends TestBase {
String alias = alias(session.getSubQueryInfo()); String alias = alias(session.getSubQueryInfo());
assert0(alias.equals("ZZ"), "select expression sub-query: " + alias); assert0(alias.equals("ZZ"), "select expression sub-query: " + alias);
assert0(session.getSubQueryInfo().getUpper() == null, "upper"); assert0(session.getSubQueryInfo().getUpper() == null, "upper");
} else if (getTable().getName().equals("QRY_EXPR_TEST")) { } else if (getTable().getName().equals("QUERY_EXPR_TEST")) {
assert0(session.isPreparingQueryExpression(), "preparing query expression"); assert0(session.isPreparingQueryExpression(), "preparing query expression");
} else if (getTable().getName().equals("QRY_EXPR_TEST_NO")) { } else if (getTable().getName().equals("QUERY_EXPR_TEST_NO")) {
assert0(!session.isPreparingQueryExpression(), "not preparing query expression"); assert0(!session.isPreparingQueryExpression(), "not preparing query expression");
} }
} }
...@@ -1588,7 +1588,7 @@ public class TestTableEngines extends TestBase { ...@@ -1588,7 +1588,7 @@ public class TestTableEngines extends TestBase {
@Override @Override
public String toString() { public String toString() {
return "IterCursor->" + current; return "IteratorCursor->" + current;
} }
} }
......
...@@ -474,7 +474,8 @@ public class TestDate extends TestBase { ...@@ -474,7 +474,8 @@ public class TestDate extends TestBase {
assertEquals("-999-08-07 13:14:15.16", ts1a.getString()); assertEquals("-999-08-07 13:14:15.16", ts1a.getString());
assertEquals("19999-08-07 13:14:15.16", ts2a.getString()); assertEquals("19999-08-07 13:14:15.16", ts2a.getString());
// test for bug on Java 1.8.0_60 in "Europe/Moscow" timezone. Doesn't affect most other timezones // test for bug on Java 1.8.0_60 in "Europe/Moscow" timezone.
// Doesn't affect most other timezones
long millis = 1407437460000L; long millis = 1407437460000L;
long result1 = DateTimeUtils.nanosFromDate(DateTimeUtils.getTimeUTCWithoutDst(millis)); long result1 = DateTimeUtils.nanosFromDate(DateTimeUtils.getTimeUTCWithoutDst(millis));
long result2 = DateTimeUtils.nanosFromDate(DateTimeUtils.getTimeUTCWithoutDst(millis)); long result2 = DateTimeUtils.nanosFromDate(DateTimeUtils.getTimeUTCWithoutDst(millis));
......
...@@ -26,13 +26,13 @@ public class TestTimeStampUtc extends TestBase { ...@@ -26,13 +26,13 @@ public class TestTimeStampUtc extends TestBase {
@Override @Override
public void test() throws SQLException { public void test() throws SQLException {
deleteDb("timestamputc"); deleteDb("timestamp_utc");
test1(); test1();
deleteDb("timestamputc"); deleteDb("timestamp_utc");
} }
private void test1() throws SQLException { private void test1() throws SQLException {
Connection conn = getConnection("timestamputc"); Connection conn = getConnection("timestamp_utc");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("create table test(id identity, t1 timestamp_utc)"); stat.execute("create table test(id identity, t1 timestamp_utc)");
stat.execute("insert into test(t1) values(0)"); stat.execute("insert into test(t1) values(0)");
......
...@@ -308,7 +308,7 @@ public class BuildBase { ...@@ -308,7 +308,7 @@ public class BuildBase {
protected int execScript(String script, StringList args) { protected int execScript(String script, StringList args) {
if (isWindows()) { if (isWindows()) {
// Under windows, we use the "cmd" command interpreter since it will // Under windows, we use the "cmd" command interpreter since it will
// search the path for us without us having to hardcode an extension // search the path for us without us having to hard-code an extension
// for the script we want. (Sometimes we don't know if the extension // for the script we want. (Sometimes we don't know if the extension
// will be .bat or .cmd) // will be .bat or .cmd)
StringList newArgs = new StringList(); StringList newArgs = new StringList();
......
...@@ -778,10 +778,8 @@ dance schedule hitting reverted youngest footers inliner deadlocked reorder nger ...@@ -778,10 +778,8 @@ dance schedule hitting reverted youngest footers inliner deadlocked reorder nger
nullid syspublic sysibmts sysibminternal syscat sysfun sysstat systools sysibmadm nullid syspublic sysibmts sysibminternal syscat sysfun sysstat systools sysibmadm
sysproc jcc expecting gpg showed unreferenced activating cvf stephane lacoin sysproc jcc expecting gpg showed unreferenced activating cvf stephane lacoin
centrale umr ecole nantes sticc lab reordering preferable simultaneously centrale umr ecole nantes sticc lab reordering preferable simultaneously
lazily satisfy participating eviction globally futures batches slot forced
--- todo diagnostic filer stamp turn going cancellation fetched produced incurring
interpreter batching fewer runners imperial correspond nine purge meridian
timestamputc lazily satisfy nexpected messager participating eviction milli globally calendars moscow messager lookups unhandled buddha parslet
futures atp lookups batches slot nnext forced tbl diagnostic filer stamp turn going tzh roc xii tzm viii myydd mar vii
nwhere hardcode cancellation qry nprev fetched produced nactual incurring interpreter
batching ncurr prefered fewer runners iter
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论