
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 java.util.logging.Level;
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