@Override protected String visitIntervalLiteral(IntervalLiteral node, Void context) { String sign = (node.getSign() == IntervalLiteral.Sign.NEGATIVE) ? "-" : ""; StringBuilder builder = new StringBuilder() .append("INTERVAL ") .append(sign) .append(" '").append(node.getValue()).append(" "); if (node.getStartField() != null) { builder.append(node.getStartField()); } else { builder.append(node.getStartText()); } if (node.getEndField() != null) { builder.append(" TO ").append(node.getEndField()); } builder.append("'"); return builder.toString(); }
private static IntervalLiteral.IntervalField getIntervalFieldType(Token token) { switch (token.getType()) { case SqlBaseLexer.YEAR: return IntervalLiteral.IntervalField.YEAR; case SqlBaseLexer.MONTH: return IntervalLiteral.IntervalField.MONTH; case SqlBaseLexer.DAY: return IntervalLiteral.IntervalField.DAY; case SqlBaseLexer.HOUR: return IntervalLiteral.IntervalField.HOUR; case SqlBaseLexer.MINUTE: return IntervalLiteral.IntervalField.MINUTE; case SqlBaseLexer.SECOND: return IntervalLiteral.IntervalField.SECOND; } throw new IllegalArgumentException("Unsupported interval field: " + token.getText()); }
protected static Expression processFuncLast(ComparisonExpression node) { System.out.println("Processing last()"); Expression rightNode = node.getRight(); Expression leftNode = node.getLeft(); FunctionCall last = (FunctionCall) rightNode; // # of arguments are already checked outside 1 or 2 String number = last.getArguments().get(0).toString(); String format = "DAY"; // default if (last.getArguments().size() == 2) { format = last.getArguments().get(1).toString().replaceAll("\"", ""); } IntervalLiteral.Sign sign; if (number.startsWith("-")) { sign = IntervalLiteral.Sign.NEGATIVE; number = number.substring(1); } else { sign = IntervalLiteral.Sign.POSITIVE; } CurrentTime cTime = new CurrentTime(CurrentTime.Type.DATE); IntervalLiteral interval = new IntervalLiteral(number, sign, format); ArithmeticExpression arithmOp = new ArithmeticExpression(ArithmeticExpression.Type.SUBTRACT, cTime, interval); BetweenPredicate bPredicate = new BetweenPredicate(leftNode, arithmOp, cTime); return bPredicate; }
@Override protected String visitIntervalLiteral(IntervalLiteral node, Void context) { String sign = (node.getSign() == IntervalLiteral.Sign.NEGATIVE) ? "-" : ""; Boolean isNumeric = isNumeric(node.getValue()); //System.out.println("############ node.getValue()==> " + node.getValue() + " numeric==> " + isNumeric); StringBuilder builder = new StringBuilder() .append("INTERVAL ") .append(sign); if (isNumeric == true) { builder.append(" '").append(node.getValue()).append("' "); } else { builder.append(node.getValue()).append(" "); } if (node.getStartField() != null) { builder.append(node.getStartField()); } else { builder.append(node.getStartText()); } if (node.getEndField() != null) { builder.append(" TO ").append(node.getEndField()); } return builder.toString(); }
@Override protected String visitIntervalLiteral(IntervalLiteral node, StackableAstVisitorContext<Integer> indent) { String sign = (node.getSign() == IntervalLiteral.Sign.NEGATIVE) ? "- " : ""; StringBuilder builder = new StringBuilder() .append("INTERVAL ") .append(sign) .append(" '").append(node.getValue()).append("' ") .append(node.getStartField()); if (node.getEndField().isPresent()) { builder.append(" TO ").append(node.getEndField().get()); } return builder.toString(); }
@Override protected RowExpression visitIntervalLiteral(IntervalLiteral node, Void context) { long value; if (node.isYearToMonth()) { value = node.getSign().multiplier() * parseYearMonthInterval(node.getValue(), node.getStartField(), node.getEndField()); } else { value = node.getSign().multiplier() * parseDayTimeInterval(node.getValue(), node.getStartField(), node.getEndField()); } return constant(value, types.get(node)); }
@Override protected Long visitIntervalLiteral(IntervalLiteral node, ConnectorSession session) { if (node.isYearToMonth()) { return node.getSign().multiplier() * parseYearMonthInterval(node.getValue(), node.getStartField(), node.getEndField()); } else { return node.getSign().multiplier() * parseDayTimeInterval(node.getValue(), node.getStartField(), node.getEndField()); } }
@Override protected Type visitIntervalLiteral(IntervalLiteral node, StackableAstVisitorContext<AnalysisContext> context) { Type type; if (node.isYearToMonth()) { type = INTERVAL_YEAR_MONTH; } else { type = INTERVAL_DAY_TIME; } expressionTypes.put(node, type); return type; }
@Override public Node visitInterval(SqlBaseParser.IntervalContext context) { return new IntervalLiteral( getLocation(context), unquote(context.STRING().getText()), Optional.ofNullable(context.sign) .map(AstBuilder::getIntervalSign) .orElse(IntervalLiteral.Sign.POSITIVE), getIntervalFieldType((Token) context.from.getChild(0).getPayload()), Optional.ofNullable(context.to) .map((x) -> x.getChild(0).getPayload()) .map(Token.class::cast) .map(AstBuilder::getIntervalFieldType)); }
private static IntervalLiteral.Sign getIntervalSign(Token token) { switch (token.getType()) { case SqlBaseLexer.MINUS: return IntervalLiteral.Sign.NEGATIVE; case SqlBaseLexer.PLUS: return IntervalLiteral.Sign.POSITIVE; } throw new IllegalArgumentException("Unsupported sign: " + token.getText()); }
@Override protected String visitIntervalLiteral(IntervalLiteral node, Boolean unmangleNames) { String sign = (node.getSign() == IntervalLiteral.Sign.NEGATIVE) ? "- " : ""; StringBuilder builder = new StringBuilder() .append("INTERVAL ") .append(sign) .append(" '").append(node.getValue()).append("' ") .append(node.getStartField()); if (node.getEndField().isPresent()) { builder.append(" TO ").append(node.getEndField().get()); } return builder.toString(); }
@Test public void testLiterals() throws Exception { assertExpression("TIME" + " 'abc'", new TimeLiteral("abc")); assertExpression("TIMESTAMP" + " 'abc'", new TimestampLiteral("abc")); assertExpression("INTERVAL '33' day", new IntervalLiteral("33", Sign.POSITIVE, IntervalField.DAY, Optional.empty())); assertExpression("INTERVAL '33' day to second", new IntervalLiteral("33", Sign.POSITIVE, IntervalField.DAY, Optional.of(IntervalField.SECOND))); }
@Test public void testInterval() throws Exception { assertExpression("INTERVAL '123' YEAR", new IntervalLiteral("123", Sign.POSITIVE, IntervalField.YEAR)); assertExpression("INTERVAL '123-3' YEAR TO MONTH", new IntervalLiteral("123-3", Sign.POSITIVE, IntervalField.YEAR, Optional.of(IntervalField.MONTH))); assertExpression("INTERVAL '123' MONTH", new IntervalLiteral("123", Sign.POSITIVE, IntervalField.MONTH)); assertExpression("INTERVAL '123' DAY", new IntervalLiteral("123", Sign.POSITIVE, IntervalField.DAY)); assertExpression("INTERVAL '123 23:58:53.456' DAY TO SECOND", new IntervalLiteral("123 23:58:53.456", Sign.POSITIVE, IntervalField.DAY, Optional.of(IntervalField.SECOND))); assertExpression("INTERVAL '123' HOUR", new IntervalLiteral("123", Sign.POSITIVE, IntervalField.HOUR)); assertExpression("INTERVAL '23:59' HOUR TO MINUTE", new IntervalLiteral("23:59", Sign.POSITIVE, IntervalField.HOUR, Optional.of(IntervalField.MINUTE))); assertExpression("INTERVAL '123' MINUTE", new IntervalLiteral("123", Sign.POSITIVE, IntervalField.MINUTE)); assertExpression("INTERVAL '123' SECOND", new IntervalLiteral("123", Sign.POSITIVE, IntervalField.SECOND)); }
protected static String processFuncDateDiff(Formatter formatter, FunctionCall node, String arguments, DBType dbType) { StringBuilder builder = new StringBuilder(); String functionName = getFunctionName(node); int numArguments = node.getArguments().size(); IntervalLiteral.IntervalField intervalField = null; // check # of arguments if (numArguments > 3 || numArguments < 2) { builder.append(functionName).append('(').append(arguments).append(')'); return builder.toString(); } // ToDo: check argument and make literal date to DATE Expression startDate = node.getArguments().get(0); Expression endDate = node.getArguments().get(1); String format = null; if (numArguments == 2) { format = "DAY"; } else { format = node.getArguments().get(2).toString().replaceAll("\"", ""); } switch (dbType) { case TERADATA: case POSTGRESQL: case ORACLE: case NETEZZA: ArithmeticExpression substract = new ArithmeticExpression(ArithmeticExpression.Type.SUBTRACT, endDate, startDate); return formatter.process(substract, null); case MYSQL: case HIVE: builder.append(functionName).append('(').append(formatter.process(endDate, null)).append(", ").append( formatter.process(startDate, null)).append(')'); return builder.toString(); case MSSQL: case REDSHIFT: case VERTICA: case AZURE: builder.append(functionName).append('(').append(format).append(", ").append( formatter.process(startDate, null)).append(", ").append(formatter.process(endDate, null)).append( ')'); return builder.toString(); case PRESTO: intervalField = dateFormat(format); builder.append("date_diff(").append("'").append(dateAccessFormat(intervalField)).append("'").append( ", ").append(formatter.process(startDate, null)).append(", ").append( formatter.process(endDate, null)).append(")"); case ACCESS: intervalField = dateFormat(format); builder.append("datediff(").append("'").append(dateAccessFormat(intervalField)).append("'").append( ", ").append(formatter.process(startDate, null)).append(", ").append( formatter.process(endDate, null)).append(")"); break; case DERBY_LOCAL: intervalField = dateFormat(format); builder.append("{fn timestampdiff(").append(dateDerbyFormat(intervalField)).append(", ").append( formatter.process(startDate, null)).append(", ").append(formatter.process(endDate, null)).append( ")}"); return builder.toString(); case DRILL: builder.append("extract(day from ").append("date_diff").append('(').append( formatter.process(endDate, null)).append(", ").append(formatter.process(startDate, null)).append( "))"); return builder.toString(); case SALESFORCE: case GOOGLEANALYTICS: builder.append(functionName).append('(').append(dateSalesforceGoogleAnalyticsFormat(intervalField)).append( ", ").append(formatter.process(startDate, null)).append(", ").append( formatter.process(endDate, null)).append(')'); return builder.toString(); default: builder.append(functionName).append('(').append(arguments).append(')'); break; } return builder.toString(); }
private static String dateSalesforceGoogleAnalyticsFormat(IntervalLiteral.IntervalField format) { String retStr = null; if (format == null) { return "'d'"; } switch (format) { case YEAR: retStr = "'yyyy'"; break; case QUARTER: retStr = "'q'"; break; case MONTH: retStr = "'m'"; break; case DAY: retStr = "'d'"; break; case WEEK: retStr = "'wk'"; break; case HOUR: retStr = "'hh'"; break; case MINUTE: retStr = "'mi'"; break; case SECOND: retStr = "'ss'"; break; case MILLISECOND: retStr = "'ms'"; break; case DAYOFYEAR: retStr = "'dy'"; break; case MICROSECOND: case NANOSECOND: default: retStr = "'d'"; break; } return retStr; }
private static String dateDerbyFormat(IntervalLiteral.IntervalField format) { String retStr = null; if (format == null) { return "SQL_TSI_DAY"; } switch (format) { case YEAR: retStr = "SQL_TSI_YEAR"; break; case QUARTER: retStr = "SQL_TSI_QUARTER"; break; case MONTH: retStr = "SQL_TSI_MONTH"; break; case DAY: retStr = "SQL_TSI_DAY"; break; case WEEK: retStr = "SQL_TSI_WEEK"; break; case HOUR: retStr = "SQL_TSI_HOUR"; break; case MINUTE: retStr = "SQL_TSI_MINUTE"; break; case SECOND: retStr = "SQL_TSI_SECOND"; break; case MILLISECOND: retStr = "SQL_TSI_FRAC_SECOND"; break; case MICROSECOND: case NANOSECOND: case DAYOFYEAR: default: retStr = "SQL_TSI_DAY"; break; } return retStr; }
private static String dateAccessFormat(IntervalLiteral.IntervalField format) { String retStr = null; if (format == null) { return "d"; } switch (format) { case YEAR: retStr = "yyyy"; break; case QUARTER: retStr = "q"; break; case MONTH: retStr = "m"; break; case DAYOFYEAR: retStr = "y"; break; case DAY: retStr = "d"; break; case WEEK: retStr = "w"; break; case HOUR: retStr = "h"; break; case MINUTE: retStr = "n"; break; case SECOND: retStr = "s"; break; case MILLISECOND: case MICROSECOND: case NANOSECOND: default: retStr = "d"; break; } return retStr; }
private static IntervalLiteral.IntervalField dateFormat(String format) { IntervalLiteral.IntervalField retIntervalField = null; format = format.toLowerCase(); switch (format) { case "year": case "yy": case "yyyy": retIntervalField = IntervalLiteral.IntervalField.YEAR; break; case "quarter": case "qq": case "q": retIntervalField = IntervalLiteral.IntervalField.QUARTER; break; case "month": case "mm": case "m": retIntervalField = IntervalLiteral.IntervalField.MONTH; break; case "dayofyear": case "dy": case "y": retIntervalField = IntervalLiteral.IntervalField.DAYOFYEAR; break; case "day": case "dd": case "d": retIntervalField = IntervalLiteral.IntervalField.DAY; break; case "week": case "wk": case "ww": retIntervalField = IntervalLiteral.IntervalField.WEEK; break; case "hour": case "hh": retIntervalField = IntervalLiteral.IntervalField.HOUR; break; case "minute": case "mi": case "n": retIntervalField = IntervalLiteral.IntervalField.MINUTE; break; case "second": case "ss": case "s": retIntervalField = IntervalLiteral.IntervalField.SECOND; break; case "millisecond": case "ms": retIntervalField = IntervalLiteral.IntervalField.MILLISECOND; break; case "microsecond": case "mcs": retIntervalField = IntervalLiteral.IntervalField.MICROSECOND; break; case "nanosecond": case "ns": retIntervalField = IntervalLiteral.IntervalField.NANOSECOND; break; default: retIntervalField = null; break; } return retIntervalField; }