Skip to content
Merged
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 @@ -13,6 +13,7 @@
import net.sf.jsqlparser.statement.select.PlainSelect;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -43,7 +44,8 @@ public enum NationalCharacterType {
private List<Integer> arrayData = new ArrayList<Integer>();
private Signedness signedness;
private boolean zerofill;
private Integer precision;
private BigInteger precision;
private boolean maxPrecision;
private Integer scale;
private List<TypeModifier> typeModifiers;
private NationalCharacterType nationalCharacterType;
Expand All @@ -55,30 +57,39 @@ public ColDataType() {

public ColDataType(String dataType, int precision, int scale) {
this(dataType);
setNumericParameters(precision < 0 ? null : Integer.valueOf(precision),
setNumericTypeParameters(precision < 0 ? null
: precision == Integer.MAX_VALUE ? "MAX" : Integer.toString(precision),
scale < 0 ? null : Integer.valueOf(scale));
}

/**
* Creates a parameterized type, using {@code null} for an omitted parameter. Unlike the legacy
* primitive constructor, this accepts negative scales, including {@code -1}.
* primitive constructor, this accepts negative scales, including {@code -1}. The legacy
* {@link Integer#MAX_VALUE} precision sentinel continues to represent MAX.
*/
public static ColDataType fromNumericParameters(String dataType, Integer precision,
Integer scale) {
return fromTypeParameters(dataType, precision == null ? null
: precision == Integer.MAX_VALUE ? "MAX" : precision.toString(), scale);
}

/**
* Creates a type from its numeric parameter spelling. Unlike the legacy primitive constructor,
* a numeric 2147483647 is distinct from MAX and larger lengths are retained without narrowing.
*/
public static ColDataType fromTypeParameters(String dataType, String precision, Integer scale) {
ColDataType type = new ColDataType(dataType);
type.setNumericParameters(precision, scale);
type.setNumericTypeParameters(precision, scale);
return type;
}

private void setNumericParameters(Integer precision, Integer scale) {
if (precision != null) {
this.precision = precision;
this.dataType += " (" + (precision == Integer.MAX_VALUE ? "MAX" : precision);
if (scale != null) {
this.scale = scale;
this.dataType += ", " + scale;
}
this.dataType += ")";
private void setNumericTypeParameters(String parameter, Integer scale) {
if (parameter != null) {
maxPrecision = "MAX".equalsIgnoreCase(parameter);
precision = maxPrecision ? null : new BigInteger(parameter);
this.scale = scale;
dataType += " (" + (maxPrecision ? "MAX" : precision)
+ (scale != null ? ", " + scale : "") + ")";
}
}

Expand All @@ -98,6 +109,54 @@ public String getDataType() {
return dataType;
}

/**
* Returns the type name without parenthesized parameters, retaining qualification, quoting and
* multiword names such as TIMESTAMP WITH TIME ZONE. The legacy {@link #getDataType()} spelling
* is unchanged. Quoted parentheses are part of an identifier and are retained.
*/
public String getBaseTypeName() {
if (dataType == null) {
return null;
}
StringBuilder name = new StringBuilder();
int depth = 0;
char quote = 0;
for (int i = 0; i < dataType.length(); i++) {
char c = dataType.charAt(i);
if (quote != 0) {
if (depth == 0) {
name.append(c);
}
if (c == quote) {
if (i + 1 < dataType.length() && dataType.charAt(i + 1) == quote) {
if (depth == 0) {
name.append(quote);
}
i++;
} else {
quote = 0;
}
}
} else if (c == '\'' || c == '"' || c == '`' || c == '[') {
quote = c == '[' ? ']' : c;
if (depth == 0) {
name.append(c);
}
} else if (c == '(') {
depth++;
while (name.length() > 0
&& Character.isWhitespace(name.charAt(name.length() - 1))) {
name.setLength(name.length() - 1);
}
} else if (c == ')' && depth > 0) {
depth--;
} else if (depth == 0) {
name.append(c);
}
}
return name.toString().trim();
}

public void setDataType(String string) {
dataType = string;
}
Expand Down Expand Up @@ -215,14 +274,35 @@ public ColDataType withXmlTypeModifier(XmlTypeModifier xmlTypeModifier) {
* The first numeric type parameter, e.g. {@code 255} for {@code VARCHAR(255)} or {@code 10} for
* {@code DECIMAL(10, 2)}. {@code MAX} is reported as {@link Integer#MAX_VALUE}. Returns
* {@code null} when the type carries no numeric parameters, e.g. {@code INT} or
* {@code ENUM('a', 'b')}.
* {@code ENUM('a', 'b')}, or when a numeric length exceeds the integer range. Use
* {@link #getNumericPrecision()} for the full range and {@link #isMaxPrecision()} to
* distinguish MAX from the numeric value 2147483647.
*/
public Integer getPrecision() {
return precision;
return maxPrecision ? Integer.valueOf(Integer.MAX_VALUE)
: precision != null && precision.bitLength() < Integer.SIZE
? Integer.valueOf(precision.intValue())
: null;
}

public void setPrecision(Integer precision) {
setNumericPrecision(precision == null ? null : BigInteger.valueOf(precision));
}

/** Returns the exact numeric parameter, or null for an omitted parameter or MAX. */
public BigInteger getNumericPrecision() {
return precision;
}

/** Updates numeric metadata without changing the legacy rendered type spelling. */
public void setNumericPrecision(BigInteger precision) {
this.precision = precision;
maxPrecision = false;
}

/** Distinguishes the MAX keyword from an equal numeric value in the legacy accessor. */
public boolean isMaxPrecision() {
return maxPrecision;
}

/**
Expand Down
12 changes: 6 additions & 6 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -15006,15 +15006,15 @@ ColDataType DataType():
ColDataType arrayType;
Integer zonePrecision = null;

Integer precision = null;
String precision = null;
Integer scale = null;
String scaleText;
}
{
(
LOOKAHEAD(2) tk=<K_TEXT_LITERAL> {
type = tk.image;
return ColDataType.fromNumericParameters(type, precision, scale);
return ColDataType.fromTypeParameters(type, precision, scale);
}
|
LOOKAHEAD(2) tk=<K_ARRAY_LITERAL> (
Expand All @@ -15041,13 +15041,13 @@ ColDataType DataType():
| tk=<K_CHAR> | tk=<K_JSON> | tk=<K_STRING> ) { type += " " + tk.image; }
)*
[
LOOKAHEAD(2) "(" ( tk=<S_LONG> { precision = Integer.valueOf(tk.image); } | tk=<K_MAX> { precision = Integer.MAX_VALUE; } )
LOOKAHEAD(2) "(" ( tk=<S_LONG> { precision = tk.image; } | tk=<K_MAX> { precision = "MAX"; } )
[ <K_BYTE> | <K_CHAR> ]
[ "," scaleText=SignedIntegerTypeArgument() { scale = Integer.valueOf(scaleText); } ]
")"
]
{
colDataType = ColDataType.fromNumericParameters(type, precision, scale);
colDataType = ColDataType.fromTypeParameters(type, precision, scale);
if (zonePrecision != null) {
colDataType.setPrecision(zonePrecision);
}
Expand Down Expand Up @@ -15254,10 +15254,10 @@ ColDataType ColDataType():
colDataType.setArgumentsStringList(argumentsStringList);
// Integer arguments expose numeric parameters, including negative scales.
if (argumentsStringList.size() == 1 && argumentsStringList.get(0).matches("\\d+")) {
colDataType.setPrecision(Integer.valueOf(argumentsStringList.get(0)));
colDataType.setNumericPrecision(new java.math.BigInteger(argumentsStringList.get(0)));
} else if (argumentsStringList.size() == 2 && argumentsStringList.get(0).matches("\\d+")
&& argumentsStringList.get(1).matches("-?\\d+")) {
colDataType.setPrecision(Integer.valueOf(argumentsStringList.get(0)));
colDataType.setNumericPrecision(new java.math.BigInteger(argumentsStringList.get(0)));
colDataType.setScale(Integer.valueOf(argumentsStringList.get(1)));
}
}
Expand Down
Loading
Loading