Skip to content

Commit 7e669a1

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 12548b9 commit 7e669a1

4 files changed

Lines changed: 45 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
@@ -19156,10 +19156,17 @@ TableOption CreateTableOption():
1915619156
option = new TableOption(); option.setStorageParameters(storageParameters);
1915719157
}
1915819158
|
19159+
LOOKAHEAD({ getToken(1).kind == K_WITHOUT && "ROWID".equalsIgnoreCase(getToken(2).image) })
19160+
<K_WITHOUT> ContextualKeyword("ROWID") {
19161+
option = new TableOption(TableOption.Kind.WITHOUT_ROWID, "WITHOUT ROWID", null, false);
19162+
}
19163+
|
1915919164
LOOKAHEAD(<K_WITHOUT> <S_IDENTIFIER>) <K_WITHOUT> ContextualKeyword("OIDS") {
1916019165
option = new TableOption(TableOption.Kind.WITHOUT_OIDS, "WITHOUT OIDS", null, false);
1916119166
}
1916219167
|
19168+
<K_STRICT> { option = new TableOption(TableOption.Kind.STRICT, "STRICT", null, false); }
19169+
|
1916319170
LOOKAHEAD(<K_ON> <K_COMMIT>) option=OnCommitTableOption()
1916419171
|
1916519172
// USING INDEX TABLESPACE stays a raw parameter

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +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.test.TestUtils;
1618
import org.junit.jupiter.api.Test;
1719
import org.junit.jupiter.params.ParameterizedTest;
1820
import org.junit.jupiter.params.provider.ValueSource;
1921

22+
import java.util.List;
2023
import java.util.Locale;
24+
import java.util.stream.Collectors;
2125

26+
import static org.junit.jupiter.api.Assertions.assertEquals;
2227
import static org.junit.jupiter.api.Assertions.assertThrows;
2328

2429
public class SQLiteTest {
@@ -52,4 +57,25 @@ void testInsertOrUnknownAlgorithm() {
5257
() -> CCJSqlParserUtil.parse("INSERT OR NOTHING INTO t VALUES (1)",
5358
parser -> parser.withDialect(Dialect.SQLITE)));
5459
}
60+
61+
@ParameterizedTest
62+
@ValueSource(strings = {
63+
"CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) WITHOUT ROWID",
64+
"CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) STRICT",
65+
"CREATE TABLE t (a INTEGER PRIMARY KEY, b BLOB) STRICT, WITHOUT ROWID",
66+
"CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) WITHOUT ROWID, STRICT",
67+
"create table t (a integer primary key) without rowid"})
68+
void testCreateTableWithoutRowidAndStrict(String sql) throws JSQLParserException {
69+
TestUtils.assertSqlCanBeParsedAndDeparsed(sql, true);
70+
}
71+
72+
@Test
73+
void testCreateTableOptionKinds() throws JSQLParserException {
74+
CreateTable createTable = (CreateTable) CCJSqlParserUtil.parse(
75+
"CREATE TABLE t (a INTEGER PRIMARY KEY) STRICT, WITHOUT ROWID");
76+
assertEquals(List.of(TableOption.Kind.STRICT, TableOption.Kind.WITHOUT_ROWID),
77+
createTable.getTableOptions().stream().map(TableOption::getKind)
78+
.collect(Collectors.toList()));
79+
}
5580
}
81+

0 commit comments

Comments
 (0)