net.snowflake.common.core.SqlFormatScanner Maven / Gradle / Ivy
/*
* Copyright (c) 2016 Snowflake Computing Inc. All right reserved.
*/
package net.snowflake.common.core;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.TimeZone;
import net.snowflake.common.util.GSCommonLogUtil;
import net.snowflake.common.util.GenericGSCommonLogger;
/** This class is used to match multiple SQL formats when parsing input strings */
public class SqlFormatScanner {
static GenericGSCommonLogger LOGGER =
GSCommonLogUtil.getLogger(MethodHandles.lookup().lookupClass());
/** The constructor */
public SqlFormatScanner() {
m_formats = new ArrayList<>();
}
/**
* Add a parsed SqlFormat to the set
*
* @param fmt parsed SqlFormat
*/
public void addFormat(SqlFormat fmt) {
m_formats.add(fmt);
}
/**
* Parse a format string with alternate input formats
*
* @param model the format model (see SqlFormat)
* @param str the format string
* @return null on success, error message on error
*/
public String setFormats(int model, String str) {
// LOGGER.log(Level.INFO, String.format(
// "SqlFormatScanner::setFormats(%d, %s)", model, str));
if (str.length() == 0) return "empty input format";
boolean gotAuto = false;
String s = str;
do {
if (s.startsWith("auto") || s.startsWith("AUTO")) {
if (s.length() == 4) s = "";
else if (s.charAt(4) != '|') return "unknown format element: '" + s + "'";
else {
s = s.substring(5);
if (s.length() == 0) return "no format elements after |";
}
if (gotAuto) return "duplicate AUTO in format list";
gotAuto = true;
switch (model) {
default:
assert false;
case SqlFormat.NUMERIC:
for (SqlFormat f : s_numFormats) m_formats.add(f);
break;
case SqlFormat.TIME:
for (SqlFormat f : s_timeFormats) m_formats.add(f);
break;
case SqlFormat.ANY:
for (SqlFormat f : s_numFormats) m_formats.add(f);
for (SqlFormat f : s_timeFormats) m_formats.add(f);
// fall through
case SqlFormat.TS_NTZ:
case SqlFormat.TS_TZ:
for (SqlFormat f : s_tsFormats) m_formats.add(f);
// fall through
case SqlFormat.DATE:
for (SqlFormat f : s_dateFormats) m_formats.add(f);
break;
}
} else {
SqlFormat f = new SqlFormat();
s = f.setFormat(model, s);
if (s == null) return f.getErrorMsg();
if (!f.checkScanModel(model)) {
switch (model) {
case SqlFormat.NUMERIC:
s = "numbers";
break;
case SqlFormat.DATE:
s = "dates";
break;
case SqlFormat.TIME:
s = "time";
break;
case SqlFormat.TS_TZ:
case SqlFormat.TS_NTZ:
s = "timestamps";
break;
}
return "missing or conflicting format elements required for parsing " + s;
}
m_formats.add(f);
}
} while (s.length() > 0);
return null;
}
/**
* Parse date using this list of formats (returns SFDate)
*
* @param str The string to parse
* @param cenBound Century boundary for YY (1900-2100)
* @return SFDate object or null on an error
*/
public SFDate parseDate(String str, int cenBound) {
TmExt tm = null;
for (SqlFormat f : m_formats) {
tm = f.parseTm(str, cenBound);
if (tm != null) break;
}
if (tm == null) return null;
return tm.getDate();
}
public SFDate parseDate(String str) {
return parseDate(str, SqlFormat.DEFAULT_CENTURY_BOUNDARY);
}
/**
* Parse time of day using this format (returns SFTime)
*
* @param str The string to parse
* @return SFTime object or null on an error
*/
public SFTime parseTime(String str) {
TmExt tm = null;
for (SqlFormat f : m_formats) {
tm = f.parseTm(str, 2000);
if (tm != null) break;
}
if (tm == null) return null;
return tm.getTime();
}
/**
* Parse timestamp using this format (returns SFTimestamp)
*
* @param str The string to parse
* @param tz the timezone to use by default
* @param cenBound Century boundary for YY (1900-2100)
* @return SFTimestamp object or null on an error
*/
public SFTimestamp parseTimestamp(String str, TimeZone tz, int cenBound) {
TmExt tm = null;
for (SqlFormat f : m_formats) {
tm = f.parseTm(str, cenBound);
if (tm != null) break;
}
if (tm == null) return null;
return tm.getTimestamp(tz);
}
public SFTimestamp parseTimestamp(String str, TimeZone tz) {
return parseTimestamp(str, tz, SqlFormat.DEFAULT_CENTURY_BOUNDARY);
}
// The list of formats in this class
private ArrayList m_formats;
// The pre-parsed AUTO formats
private static final ArrayList s_numFormats;
private static final ArrayList s_timeFormats;
private static final ArrayList s_dateFormats;
private static final ArrayList s_tsFormats;
static {
//
// The lists of default AUTO formats for various models
// NB: THESE LIST MUST MATCH THE LISTS IN XP's SqlFormatParams.cpp
//
final String autoNum[] = {"TM9", "TME"};
s_numFormats = new ArrayList<>();
for (String s : autoNum) {
SqlFormat f = new SqlFormat();
String res = f.setFormat(SqlFormat.NUMERIC, s);
assert res != null && res.equals("");
assert f.checkScanModel(SqlFormat.NUMERIC);
s_numFormats.add(f);
}
final String autoTime[] = {
"HH24:MI", "HH24:MI:SS", "HH24:MI:SS.FF", "HH12:MI_AM", "HH12:MI:SS_AM", "HH12:MI:SS.FF_AM"
};
s_timeFormats = new ArrayList<>();
for (String s : autoTime) {
SqlFormat f = new SqlFormat();
String res = f.setFormat(SqlFormat.TIME, s);
assert res != null && res.equals("");
assert f.checkScanModel(SqlFormat.TIME);
s_timeFormats.add(f);
}
final String autoDate[] = {"YYYY-MM-DD", "YYYY-MON-DD", "DD-MON-YYYY", "MM/DD/YYYY"};
s_dateFormats = new ArrayList<>();
for (String s : autoDate) {
SqlFormat f = new SqlFormat();
String res = f.setFormat(SqlFormat.DATE, s);
assert res != null && res.equals("");
assert f.checkScanModel(SqlFormat.DATE);
s_dateFormats.add(f);
}
final String autoTs[] = {
// ISO-ish
"YYYY-MM-DD\"T\"HH24:MI",
"YYYY-MM-DD\"T\"HH24:MI:SS",
"YYYY-MM-DD\"T\"HH24:MI:SS.FF",
"YYYY-MM-DD\"T\"HH24:MITZISO",
"YYYY-MM-DD\"T\"HH24:MI:SSTZISO",
"YYYY-MM-DD\"T\"HH24:MI:SS.FFTZISO",
// ?
"YYYY-MM-DD HH24:MI",
"YYYY-MM-DD HH24:MI:SS",
"YYYY-MM-DD HH24:MI:SS.FF",
"YYYY-MM-DD HH24:MI_TZH:TZM",
"YYYY-MM-DD HH24:MI:SS_TZH:TZM",
"YYYY-MM-DD HH24:MI:SS.FF_TZH:TZM",
"YYYY-MM-DD HH24:MI_TZISO",
"YYYY-MM-DD HH24:MI:SS_TZISO",
"YYYY-MM-DD HH24:MI:SS.FF_TZISO",
// RFC-ish
"Dy, DD Mon YYYY HH24:MI:SS",
"Dy, DD Mon YYYY HH24:MI:SS.FF",
"Dy, DD Mon YYYY HH12:MI:SS_AM",
"Dy, DD Mon YYYY HH12:MI:SS.FF_AM",
"Dy, DD Mon YYYY HH24:MI:SS TZHTZM",
"Dy, DD Mon YYYY HH24:MI:SS.FF TZHTZM",
"Dy, DD Mon YYYY HH12:MI:SS_AM TZHTZM",
"Dy, DD Mon YYYY HH12:MI:SS.FF_AM TZHTZM",
// Misc
"MM/DD/YYYY HH24:MI:SS",
"MM/DD/YYYY HH24:MI:SS.FF",
// Twitter
"Dy Mon DD HH24:MI:SS TZHTZM YYYY",
};
s_tsFormats = new ArrayList<>();
for (String s : autoTs) {
SqlFormat f = new SqlFormat();
String res = f.setFormat(SqlFormat.TS_TZ, s);
assert res != null && res.equals("");
assert f.checkScanModel(SqlFormat.TS_TZ);
s_tsFormats.add(f);
}
}
}
;
© 2015 - 2025 Weber Informatics LLC | Privacy Policy