All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.snowflake.common.core.SqlFormatScanner Maven / Gradle / Ivy

There is a newer version: 5.1.4
Show newest version
/*
 * 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