Skip to content

Commit bb2f269

Browse files
authored
fix(parser): model MySQL column type modifiers (#2537)
1 parent 2243e2b commit bb2f269

3 files changed

Lines changed: 71 additions & 4 deletions

File tree

src/main/java/net/sf/jsqlparser/statement/create/table/ColDataType.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,17 @@
2424

2525
public class ColDataType implements Serializable {
2626

27+
public enum Signedness {
28+
SIGNED, UNSIGNED
29+
}
30+
2731
private String dataType;
2832
private List<String> argumentsStringList;
2933
private String characterSet;
3034
private IntervalQualifier intervalQualifier;
3135
private List<Integer> arrayData = new ArrayList<Integer>();
36+
private Signedness signedness;
37+
private boolean zerofill;
3238
private Integer precision;
3339
private Integer scale;
3440

@@ -98,6 +104,22 @@ public void setArrayData(List<Integer> arrayData) {
98104
this.arrayData = arrayData;
99105
}
100106

107+
public Signedness getSignedness() {
108+
return signedness;
109+
}
110+
111+
public void setSignedness(Signedness signedness) {
112+
this.signedness = signedness;
113+
}
114+
115+
public boolean isZerofill() {
116+
return zerofill;
117+
}
118+
119+
public void setZerofill(boolean zerofill) {
120+
this.zerofill = zerofill;
121+
}
122+
101123
/**
102124
* The first numeric type parameter, e.g. {@code 255} for {@code VARCHAR(255)} or {@code 10} for
103125
* {@code DECIMAL(10, 2)}. {@code MAX} is reported as {@link Integer#MAX_VALUE}. Returns
@@ -139,6 +161,8 @@ public String toString() {
139161
+ (argumentsStringList != null
140162
? " " + PlainSelect.getStringList(argumentsStringList, true, true)
141163
: "")
164+
+ (signedness != null ? " " + signedness : "")
165+
+ (zerofill ? " ZEROFILL" : "")
142166
+ arraySpec.toString()
143167
+ (characterSet != null ? " CHARACTER SET " + characterSet : "");
144168
}
@@ -168,6 +192,16 @@ public ColDataType withArrayData(List<Integer> arrayData) {
168192
return this;
169193
}
170194

195+
public ColDataType withSignedness(Signedness signedness) {
196+
setSignedness(signedness);
197+
return this;
198+
}
199+
200+
public ColDataType withZerofill(boolean zerofill) {
201+
setZerofill(zerofill);
202+
return this;
203+
}
204+
171205
public ColDataType withPrecision(Integer precision) {
172206
this.setPrecision(precision);
173207
return this;
@@ -218,7 +252,9 @@ public final boolean equals(Object o) {
218252
&& Objects.equals(argumentsStringList, that.argumentsStringList)
219253
&& Objects.equals(characterSet, that.characterSet)
220254
&& Objects.equals(intervalQualifier, that.intervalQualifier)
221-
&& Objects.equals(arrayData, that.arrayData);
255+
&& Objects.equals(arrayData, that.arrayData)
256+
&& signedness == that.signedness
257+
&& zerofill == that.zerofill;
222258
}
223259

224260
@Override
@@ -228,6 +264,8 @@ public int hashCode() {
228264
result = 31 * result + Objects.hashCode(characterSet);
229265
result = 31 * result + Objects.hashCode(intervalQualifier);
230266
result = 31 * result + Objects.hashCode(arrayData);
267+
result = 31 * result + Objects.hashCode(signedness);
268+
result = 31 * result + Boolean.hashCode(zerofill);
231269
return result;
232270
}
233271
}

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,7 @@ String NonReservedWord() :
18311831
| tk=<K_XSINIL:"XSINIL">
18321832
| tk=<K_YAML:"YAML">
18331833
| tk=<K_YES:"YES">
1834+
| tk=<K_ZEROFILL:"ZEROFILL">
18341835
| tk=<K_ZONE:"ZONE">
18351836
)
18361837
{ return tk.image; }
@@ -11794,10 +11795,10 @@ ColDataType DataType():
1179411795
zonePrecision = tk.kind == DT_ZONE ? zonedTypePrecision(tk.image) : null;
1179511796
}
1179611797
(
11797-
// MySQL seems to allow: INT UNSIGNED. Do not consume CHARACTER when it starts
11798-
// the trailing CHARACTER SET clause of a character type.
11798+
// Signedness is parsed by ColDataType after optional precision/scale. Do not
11799+
// consume CHARACTER when it starts the trailing CHARACTER SET clause.
1179911800
LOOKAHEAD(2, { getToken(1).kind != K_CHARACTER || getToken(2).kind != K_SET })
11800-
( tk = <DATA_TYPE> | tk = <K_SIGNED> | tk = <K_UNSIGNED>
11801+
( tk = <DATA_TYPE>
1180111802
| tk=<K_CHARACTER> | tk=<K_BIT> | tk=<K_BYTES> | tk=<K_BINARY> | tk=<K_BOOLEAN>
1180211803
| tk=<K_CHAR> | tk=<K_JSON> | tk=<K_STRING> ) { type += " " + tk.image; }
1180311804
)*
@@ -11926,6 +11927,11 @@ ColDataType ColDataType():
1192611927
)*
1192711928
")"
1192811929
]
11930+
[ LOOKAHEAD(2)
11931+
( tk=<K_SIGNED> { colDataType.setSignedness(ColDataType.Signedness.SIGNED); }
11932+
| tk=<K_UNSIGNED> { colDataType.setSignedness(ColDataType.Signedness.UNSIGNED); } )
11933+
]
11934+
[ LOOKAHEAD(2) <K_ZEROFILL> { colDataType.setZerofill(true); } ]
1192911935
[ LOOKAHEAD(2) ( LOOKAHEAD(2) "[" {tk=null;} [ tk=<S_LONG> ] { array.add(tk!=null?Integer.valueOf(tk.image):null); } "]" )+ { colDataType.setArrayData(array); } ]
1193011936
[ LOOKAHEAD(2) <K_CHARACTER> <K_SET> (tk=<S_IDENTIFIER> | tk=<K_BINARY>) { colDataType.setCharacterSet(tk.image); } ]
1193111937

src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import net.sf.jsqlparser.schema.Column;
3636
import net.sf.jsqlparser.schema.Table;
3737
import net.sf.jsqlparser.statement.create.table.ColDataType;
38+
import net.sf.jsqlparser.statement.create.table.ColDataType.Signedness;
3839
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
3940
import net.sf.jsqlparser.statement.create.table.CreateTable;
4041
import net.sf.jsqlparser.statement.create.table.ExcludeConstraint;
@@ -1255,6 +1256,28 @@ void testUniqueIndexIssue1893() throws JSQLParserException {
12551256
assertSqlCanBeParsedAndDeparsed("CREATE TABLE t (a int, INDEX idx (a))", true);
12561257
}
12571258

1259+
@Test
1260+
void testMySqlColumnTypeModifiers() throws JSQLParserException {
1261+
String sql = "CREATE TABLE t (a INT UNSIGNED, b INT (11) UNSIGNED ZEROFILL, "
1262+
+ "c DECIMAL (10, 2) SIGNED NOT NULL)";
1263+
CreateTable createTable =
1264+
(CreateTable) assertSqlCanBeParsedAndDeparsed(sql, true);
1265+
1266+
ColDataType first = createTable.getColumnDefinitions().get(0).getColDataType();
1267+
assertEquals("INT", first.getDataType());
1268+
assertEquals(Signedness.UNSIGNED, first.getSignedness());
1269+
assertFalse(first.isZerofill());
1270+
1271+
ColDataType second = createTable.getColumnDefinitions().get(1).getColDataType();
1272+
assertEquals(Signedness.UNSIGNED, second.getSignedness());
1273+
assertTrue(second.isZerofill());
1274+
1275+
ColDataType third = createTable.getColumnDefinitions().get(2).getColDataType();
1276+
assertEquals(Signedness.SIGNED, third.getSignedness());
1277+
assertEquals(List.of("NOT", "NULL"),
1278+
createTable.getColumnDefinitions().get(2).getColumnSpecs());
1279+
}
1280+
12581281
@Test
12591282
void testMySqlConstraintSymbolAndIndexNameIssue1570() throws JSQLParserException {
12601283
String uniqueSql = "CREATE TABLE table1 (col1 INT, col2 INT UNIQUE, "

0 commit comments

Comments
 (0)