Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class IntervalExpression extends ASTNodeAccessImpl implements Expression
private final boolean intervalKeyword;
private String parameter = null;
private String intervalType = null;
private IntervalQualifier intervalQualifier = null;
private Expression expression = null;

public IntervalExpression() {
Expand Down Expand Up @@ -47,12 +48,42 @@ public void setParameter(String parameter) {
this.parameter = parameter;
}

/**
* Returns the non-standard single-identifier interval type (e.g. MySQL {@code INTERVAL 1 foo}),
* or {@code null} when a structured {@link IntervalQualifier} is present.
*
* @deprecated the structured {@link #getIntervalQualifier()} is the canonical representation.
* This legacy field is kept only for the non-standard single-identifier form.
* @return the legacy interval type, or {@code null} if a qualifier is set
*/
@Deprecated
public String getIntervalType() {
return intervalType;
}

/**
* Sets the non-standard single-identifier interval type (e.g. MySQL {@code INTERVAL 1 foo}) and
* clears any structured qualifier.
*
* @deprecated use {@link #setIntervalQualifier(IntervalQualifier)} for the standard form.
* @param intervalType the legacy interval type
*/
@Deprecated
public void setIntervalType(String intervalType) {
this.intervalType = intervalType;
this.intervalQualifier = null;
}

public IntervalQualifier getIntervalQualifier() {
return intervalQualifier;
}

/**
* Sets the structured interval qualifier and clears the legacy interval type.
*/
public void setIntervalQualifier(IntervalQualifier intervalQualifier) {
this.intervalQualifier = intervalQualifier;
this.intervalType = null;
}

public Expression getExpression() {
Expand All @@ -67,7 +98,9 @@ public void setExpression(Expression expression) {
public String toString() {
return (intervalKeyword ? "INTERVAL " : "")
+ Objects.toString(expression, parameter)
+ (intervalType != null ? " " + intervalType : "");
+ (intervalQualifier != null
? " " + intervalQualifier.toString()
: (intervalType != null ? " " + intervalType : ""));
}

@Override
Expand All @@ -80,11 +113,22 @@ public IntervalExpression withParameter(String parameter) {
return this;
}

/**
* @deprecated use {@link #withIntervalQualifier(IntervalQualifier)} for the standard form.
* @param intervalType the legacy interval type
* @return this instance
*/
@Deprecated
public IntervalExpression withIntervalType(String intervalType) {
this.setIntervalType(intervalType);
return this;
}

public IntervalExpression withIntervalQualifier(IntervalQualifier intervalQualifier) {
this.setIntervalQualifier(intervalQualifier);
return this;
}

public IntervalExpression withExpression(Expression expression) {
this.setExpression(expression);
return this;
Expand Down
123 changes: 123 additions & 0 deletions src/main/java/net/sf/jsqlparser/expression/IntervalQualifier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2019 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.expression;

import java.io.Serializable;
import java.util.Objects;

/**
* Models an SQL interval qualifier as defined by the SQL standard (see
* <a href="https://www.postgresql.org/docs/current/datatype-datetime.html">PostgreSQL: Interval
* Input</a>), e.g. {@code YEAR}, {@code DAY TO SECOND}, {@code DAY(9) TO SECOND} or
* {@code SECOND(2, 4)}.
* <p>
* It is shared by {@link IntervalExpression} (the {@code INTERVAL ...} expression literal, used in
* DML) and by {@code net.sf.jsqlparser.statement.create.table.ColDataType} (the {@code INTERVAL}
* column / cast target type, used in DDL), so the qualifier is represented once and round-trips
* consistently across all contexts.
*/
public final class IntervalQualifier implements Serializable {

private final String leadingField;
private final Integer leadingFieldPrecision;
private final String trailingField;
private final Integer fractionalSecondsPrecision;

public IntervalQualifier(
String leadingField, Integer leadingFieldPrecision, String trailingField,
Integer fractionalSecondsPrecision) {
this.leadingField = leadingField;
this.leadingFieldPrecision = leadingFieldPrecision;
this.trailingField = trailingField;
this.fractionalSecondsPrecision = fractionalSecondsPrecision;
}

public String getLeadingField() {
return leadingField;
}

public Integer getLeadingFieldPrecision() {
return leadingFieldPrecision;
}

public String getTrailingField() {
return trailingField;
}

public Integer getFractionalSecondsPrecision() {
return fractionalSecondsPrecision;
}

public IntervalQualifier withLeadingField(String leadingField) {
return new IntervalQualifier(
leadingField, leadingFieldPrecision, trailingField, fractionalSecondsPrecision);
}

public IntervalQualifier withLeadingFieldPrecision(Integer leadingFieldPrecision) {
return new IntervalQualifier(
leadingField, leadingFieldPrecision, trailingField, fractionalSecondsPrecision);
}

public IntervalQualifier withTrailingField(String trailingField) {
return new IntervalQualifier(
leadingField, leadingFieldPrecision, trailingField, fractionalSecondsPrecision);
}

public IntervalQualifier withFractionalSecondsPrecision(Integer fractionalSecondsPrecision) {
return new IntervalQualifier(
leadingField, leadingFieldPrecision, trailingField, fractionalSecondsPrecision);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof IntervalQualifier)) {
return false;
}
IntervalQualifier that = (IntervalQualifier) o;
return Objects.equals(leadingField, that.leadingField)
&& Objects.equals(leadingFieldPrecision, that.leadingFieldPrecision)
&& Objects.equals(trailingField, that.trailingField)
&& Objects.equals(fractionalSecondsPrecision, that.fractionalSecondsPrecision);
}

@Override
public int hashCode() {
return Objects.hash(
leadingField, leadingFieldPrecision, trailingField, fractionalSecondsPrecision);
}

/**
* Renders the qualifier back to SQL, e.g. {@code DAY}, {@code DAY TO SECOND},
* {@code DAY(9) TO SECOND} or {@code SECOND(2, 4)}.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder(Objects.toString(leadingField, ""));
if (leadingFieldPrecision != null) {
sb.append("(").append(leadingFieldPrecision);
// For a single-field qualifier such as SECOND(2, 4), the fractional seconds
// precision is rendered together with the leading precision.
if (trailingField == null && fractionalSecondsPrecision != null) {
sb.append(", ").append(fractionalSecondsPrecision);
}
sb.append(")");
}
if (trailingField != null) {
sb.append(" TO ").append(trailingField);
if (fractionalSecondsPrecision != null) {
sb.append("(").append(fractionalSecondsPrecision).append(")");
}
}
return sb.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
package net.sf.jsqlparser.statement.create.table;

import net.sf.jsqlparser.expression.IntervalQualifier;
import net.sf.jsqlparser.statement.select.PlainSelect;

import java.io.Serializable;
Expand All @@ -26,6 +27,7 @@ public class ColDataType implements Serializable {
private String dataType;
private List<String> argumentsStringList;
private String characterSet;
private IntervalQualifier intervalQualifier;
private List<Integer> arrayData = new ArrayList<Integer>();

public ColDataType() {
Expand Down Expand Up @@ -76,6 +78,14 @@ public void setCharacterSet(String characterSet) {
this.characterSet = characterSet;
}

public IntervalQualifier getIntervalQualifier() {
return intervalQualifier;
}

public void setIntervalQualifier(IntervalQualifier intervalQualifier) {
this.intervalQualifier = intervalQualifier;
}

public List<Integer> getArrayData() {
return arrayData;
}
Expand All @@ -95,6 +105,7 @@ public String toString() {
arraySpec.append("]");
}
return dataType
+ (intervalQualifier != null ? " " + intervalQualifier.toString() : "")
+ (argumentsStringList != null
? " " + PlainSelect.getStringList(argumentsStringList, true, true)
: "")
Expand All @@ -117,6 +128,11 @@ public ColDataType withCharacterSet(String characterSet) {
return this;
}

public ColDataType withIntervalQualifier(IntervalQualifier intervalQualifier) {
this.setIntervalQualifier(intervalQualifier);
return this;
}

public ColDataType withArrayData(List<Integer> arrayData) {
this.setArrayData(arrayData);
return this;
Expand Down Expand Up @@ -161,6 +177,7 @@ public final boolean equals(Object o) {
return dataType.equalsIgnoreCase(that.dataType)
&& Objects.equals(argumentsStringList, that.argumentsStringList)
&& Objects.equals(characterSet, that.characterSet)
&& Objects.equals(intervalQualifier, that.intervalQualifier)
&& Objects.equals(arrayData, that.arrayData);
}

Expand All @@ -169,6 +186,7 @@ public int hashCode() {
int result = dataType.hashCode();
result = 31 * result + Objects.hashCode(argumentsStringList);
result = 31 * result + Objects.hashCode(characterSet);
result = 31 * result + Objects.hashCode(intervalQualifier);
result = 31 * result + Objects.hashCode(arrayData);
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,10 @@ public <S> StringBuilder visit(ExtractExpression extractExpression, S context) {
}

@Override
@SuppressWarnings("deprecation")
// The deparser must round-trip both the canonical IntervalQualifier and the deprecated
// legacy interval type (non-standard form such as MySQL INTERVAL 1 foo), so it reads
// getIntervalType() intentionally.
public <S> StringBuilder visit(IntervalExpression intervalExpression, S context) {
if (intervalExpression.isUsingIntervalKeyword()) {
builder.append("INTERVAL ");
Expand All @@ -1320,7 +1324,9 @@ public <S> StringBuilder visit(IntervalExpression intervalExpression, S context)
} else {
builder.append(intervalExpression.getParameter());
}
if (intervalExpression.getIntervalType() != null) {
if (intervalExpression.getIntervalQualifier() != null) {
builder.append(" ").append(intervalExpression.getIntervalQualifier().toString());
} else if (intervalExpression.getIntervalType() != null) {
builder.append(" ").append(intervalExpression.getIntervalType());
}
return builder;
Expand Down
Loading
Loading