Skip to content

Commit 72284c7

Browse files
committed
feat: parse SQLite WITHOUT ROWID and STRICT table options
SQLite takes a comma-separated list of WITHOUT ROWID and STRICT after the column list. Both are now TableOption kinds, and the deparser keeps the comma SQLite requires between them. Part of #2852
1 parent e27929f commit 72284c7

4 files changed

Lines changed: 43 additions & 2 deletions

File tree

‎src/main/java/net/sf/jsqlparser/statement/create/table/CreateTable.java‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,9 +570,14 @@ private void appendColumnDefinitions(StringBuilder b) {
570570
public void appendTableOptionsTo(StringBuilder builder,
571571
java.util.function.Consumer<net.sf.jsqlparser.expression.Expression> expressionPrinter) {
572572
if (tableOptions != null) {
573+
TableOption previous = null;
573574
for (TableOption option : tableOptions) {
574-
builder.append(' ');
575+
// SQLite requires a comma between WITHOUT ROWID and STRICT
576+
builder.append(isSqliteTableOption(previous) && isSqliteTableOption(option)
577+
? ", "
578+
: " ");
575579
option.appendTo(builder, expressionPrinter);
580+
previous = option;
576581
}
577582
} else {
578583
String options = PlainSelect.getStringList(tableOptionsStrings, false, false);
@@ -582,6 +587,11 @@ public void appendTableOptionsTo(StringBuilder builder,
582587
}
583588
}
584589

590+
private static boolean isSqliteTableOption(TableOption option) {
591+
return option != null && (option.getKind() == TableOption.Kind.WITHOUT_ROWID
592+
|| option.getKind() == TableOption.Kind.STRICT);
593+
}
594+
585595
private void appendTableOptions(StringBuilder b) {
586596
if (partitioning != null && tableOptionsAfterPartition) {
587597
b.append(" ").append(partitioning);

‎src/main/java/net/sf/jsqlparser/statement/create/table/TableOption.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public class TableOption implements Serializable {
3939
private StringValue comment;
4040

4141
public enum Kind {
42-
ENGINE, CHARACTER_SET, COLLATE, COMMENT, AUTO_INCREMENT, STATS_AUTO_RECALC, STATS_PERSISTENT, STATS_SAMPLE_PAGES, UNION, ENCRYPTION, PASSWORD, DATA_DIRECTORY, INDEX_DIRECTORY, SECONDARY_ENGINE, AUTOEXTEND_SIZE, INSERT_METHOD, PACK_KEYS, DELAY_KEY_WRITE, CHECKSUM, CONNECTION, COMPRESSION, STORAGE_PARAMETERS, WITHOUT_OIDS, ENGINE_ATTRIBUTE, SECONDARY_ENGINE_ATTRIBUTE, ROW_FORMAT, AVG_ROW_LENGTH, MAX_ROWS, MIN_ROWS, KEY_BLOCK_SIZE, TABLESPACE, FOREIGN_SERVER, ACCESS_METHOD, ON_COMMIT, FILE_BLOCK_SIZE, OTHER
42+
ENGINE, CHARACTER_SET, COLLATE, COMMENT, AUTO_INCREMENT, STATS_AUTO_RECALC, STATS_PERSISTENT, STATS_SAMPLE_PAGES, UNION, ENCRYPTION, PASSWORD, DATA_DIRECTORY, INDEX_DIRECTORY, SECONDARY_ENGINE, AUTOEXTEND_SIZE, INSERT_METHOD, PACK_KEYS, DELAY_KEY_WRITE, CHECKSUM, CONNECTION, COMPRESSION, STORAGE_PARAMETERS, WITHOUT_OIDS, WITHOUT_ROWID, STRICT, ENGINE_ATTRIBUTE, SECONDARY_ENGINE_ATTRIBUTE, ROW_FORMAT, AVG_ROW_LENGTH, MAX_ROWS, MIN_ROWS, KEY_BLOCK_SIZE, TABLESPACE, FOREIGN_SERVER, ACCESS_METHOD, ON_COMMIT, FILE_BLOCK_SIZE, OTHER
4343
}
4444

4545
/**

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19798,10 +19798,17 @@ TableOption CreateTableOption():
1979819798
option = new TableOption(); option.setStorageParameters(storageParameters);
1979919799
}
1980019800
|
19801+
LOOKAHEAD({ getToken(1).kind == K_WITHOUT && "ROWID".equalsIgnoreCase(getToken(2).image) })
19802+
<K_WITHOUT> ContextualKeyword("ROWID") {
19803+
option = new TableOption(TableOption.Kind.WITHOUT_ROWID, "WITHOUT ROWID", null, false);
19804+
}
19805+
|
1980119806
LOOKAHEAD(<K_WITHOUT> <S_IDENTIFIER>) <K_WITHOUT> ContextualKeyword("OIDS") {
1980219807
option = new TableOption(TableOption.Kind.WITHOUT_OIDS, "WITHOUT OIDS", null, false);
1980319808
}
1980419809
|
19810+
<K_STRICT> { option = new TableOption(TableOption.Kind.STRICT, "STRICT", null, false); }
19811+
|
1980519812
LOOKAHEAD(<K_ON> <K_COMMIT>) option=OnCommitTableOption()
1980619813
|
1980719814
// USING INDEX TABLESPACE stays a raw parameter

‎src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,18 @@
1212
import net.sf.jsqlparser.JSQLParserException;
1313
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
1414
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
15+
import net.sf.jsqlparser.statement.create.table.CreateTable;
16+
import net.sf.jsqlparser.statement.create.table.TableOption;
1517
import net.sf.jsqlparser.statement.update.Update;
1618
import net.sf.jsqlparser.statement.update.UpdateConflictAlgorithm;
1719
import net.sf.jsqlparser.test.TestUtils;
1820
import org.junit.jupiter.api.Test;
1921
import org.junit.jupiter.params.ParameterizedTest;
2022
import org.junit.jupiter.params.provider.ValueSource;
2123

24+
import java.util.List;
2225
import java.util.Locale;
26+
import java.util.stream.Collectors;
2327

2428
import static org.junit.jupiter.api.Assertions.assertEquals;
2529
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -94,4 +98,24 @@ void testUpdateWithoutConflictAlgorithm() throws JSQLParserException {
9498
"UPDATE t SET a = 1", true, parser -> parser.withDialect(Dialect.SQLITE));
9599
assertNull(update.getConflictAlgorithm());
96100
}
101+
102+
@ParameterizedTest
103+
@ValueSource(strings = {
104+
"CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) WITHOUT ROWID",
105+
"CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) STRICT",
106+
"CREATE TABLE t (a INTEGER PRIMARY KEY, b BLOB) STRICT, WITHOUT ROWID",
107+
"CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) WITHOUT ROWID, STRICT",
108+
"create table t (a integer primary key) without rowid"})
109+
void testCreateTableWithoutRowidAndStrict(String sql) throws JSQLParserException {
110+
TestUtils.assertSqlCanBeParsedAndDeparsed(sql, true);
111+
}
112+
113+
@Test
114+
void testCreateTableOptionKinds() throws JSQLParserException {
115+
CreateTable createTable = (CreateTable) CCJSqlParserUtil.parse(
116+
"CREATE TABLE t (a INTEGER PRIMARY KEY) STRICT, WITHOUT ROWID");
117+
assertEquals(List.of(TableOption.Kind.STRICT, TableOption.Kind.WITHOUT_ROWID),
118+
createTable.getTableOptions().stream().map(TableOption::getKind)
119+
.collect(Collectors.toList()));
120+
}
97121
}

0 commit comments

Comments
 (0)