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 @@ -548,7 +548,7 @@ private static StmtResult columnsResult(StmtResult raw) {

ColumnShape shape = columnShape(declaredType);
boolean autoIncrement = primaryKey
&& LibsqlResultSetMetaData.isAutoIncrementColumn(createSql, columnName);
&& SqlAutoIncrement.isAutoIncrementColumn(createSql, columnName);
boolean generated = hidden == 2 || hidden == 3;

rows.add(new Row(List.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,9 @@ private Col getCol(int column) throws SQLException {
public boolean isAutoIncrement(int column) throws SQLException {
TableInfo table = tableForColumn(column);
ColumnInfo info = table != null ? table.columns().get(columnName(column)) : null;
return info != null && info.primaryKey() && isAutoIncrementColumn(table.createSql(), columnName(column));
}

static boolean isAutoIncrementColumn(String createSql, String columnName) {
if (createSql == null || columnName == null) {
return false;
}
List<List<SqlTokenizer.Token>> definitions = tableDefinitions(createSql);
if (definitions == null) {
return false;
}
for (List<SqlTokenizer.Token> definition : definitions) {
if (columnDefinitionIsAutoIncrement(definition, columnName)
|| tableConstraintIsAutoIncrement(definition, columnName)) {
return true;
}
}
return false;
return info != null
&& info.primaryKey()
&& SqlAutoIncrement.isAutoIncrementColumn(table.createSql(), columnName(column));
}

@Override
Expand Down Expand Up @@ -526,127 +511,6 @@ private static TableInfo toTableInfo(StmtResult result, String fallbackName) {
return new TableInfo(tableName != null ? tableName : fallbackName, createSql, columns);
}

private static List<List<SqlTokenizer.Token>> tableDefinitions(String createSql) {
List<SqlTokenizer.Token> tokens = SqlTokenizer.tokenize(createSql);
if (tokens == null) {
return null;
}
int open = -1;
for (int i = 0; i < tokens.size(); i++) {
if (tokens.get(i).isSymbol("(")) {
open = i;
break;
}
}
if (open < 0) {
return null;
}

List<List<SqlTokenizer.Token>> definitions = new ArrayList<>();
List<SqlTokenizer.Token> current = new ArrayList<>();
for (int i = open + 1; i < tokens.size(); i++) {
SqlTokenizer.Token token = tokens.get(i);
if (token.isSymbol(")") && token.depth() == 0) {
if (!current.isEmpty()) {
definitions.add(current);
}
return definitions;
}
if (token.isSymbol(",") && token.depth() == 1) {
definitions.add(current);
current = new ArrayList<>();
continue;
}
current.add(token);
}
return null;
}

private static boolean columnDefinitionIsAutoIncrement(
List<SqlTokenizer.Token> definition, String columnName) {
int start = skipConstraintName(definition);
if (start >= definition.size()) {
return false;
}
if (isConstraintKeyword(definition.get(start))) {
return false;
}
String name = definition.get(start).identifier();
if (name == null || !name.equalsIgnoreCase(columnName)) {
return false;
}
return containsKeyword(definition, start + 1, definition.size(), "AUTOINCREMENT", 1);
}

private static boolean tableConstraintIsAutoIncrement(
List<SqlTokenizer.Token> definition, String columnName) {
int start = skipConstraintName(definition);
if (start + 1 >= definition.size()
|| !definition.get(start).isWord("PRIMARY")
|| !definition.get(start + 1).isWord("KEY")) {
return false;
}
int open = -1;
for (int i = start + 2; i < definition.size(); i++) {
if (definition.get(i).isSymbol("(")) {
open = i;
break;
}
}
if (open < 0) {
return false;
}

int partStart = open + 1;
for (int i = open + 1; i < definition.size(); i++) {
SqlTokenizer.Token token = definition.get(i);
if ((token.isSymbol(",") && token.depth() == 2)
|| (token.isSymbol(")") && token.depth() == 1)) {
if (indexedColumnIsAutoIncrement(definition, partStart, i, columnName)) {
return true;
}
partStart = i + 1;
}
}
return false;
}

private static boolean indexedColumnIsAutoIncrement(
List<SqlTokenizer.Token> definition, int start, int end, String columnName) {
if (start >= end) {
return false;
}
String name = definition.get(start).identifier();
return name != null
&& name.equalsIgnoreCase(columnName)
&& containsKeyword(definition, start + 1, end, "AUTOINCREMENT", 2);
}

private static int skipConstraintName(List<SqlTokenizer.Token> definition) {
if (definition.size() >= 2 && definition.get(0).isWord("CONSTRAINT")) {
return 2;
}
return 0;
}

private static boolean isConstraintKeyword(SqlTokenizer.Token token) {
return token.isWord("PRIMARY")
|| token.isWord("UNIQUE")
|| token.isWord("CHECK")
|| token.isWord("FOREIGN");
}

private static boolean containsKeyword(
List<SqlTokenizer.Token> tokens, int start, int end, String keyword, int depth) {
for (int i = start; i < end; i++) {
SqlTokenizer.Token token = tokens.get(i);
if (token.depth() == depth && token.isWord(keyword)) {
return true;
}
}
return false;
}

private static String text(Value value) {
return value instanceof Value.Text t ? t.value() : null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package com.github.magnusp.libsql.jdbc;

import java.util.ArrayList;
import java.util.List;

/** SQLite AUTOINCREMENT grammar for a column definition. */
final class SqlAutoIncrement {

private SqlAutoIncrement() {}

static boolean isAutoIncrementColumn(String createSql, String columnName) {
if (createSql == null || columnName == null) {
return false;
}
List<List<SqlTokenizer.Token>> definitions = tableDefinitions(createSql);
if (definitions == null) {
return false;
}
for (List<SqlTokenizer.Token> definition : definitions) {
if (columnDefinitionIsAutoIncrement(definition, columnName)
|| tableConstraintIsAutoIncrement(definition, columnName)) {
return true;
}
}
return false;
}

private static List<List<SqlTokenizer.Token>> tableDefinitions(String createSql) {
List<SqlTokenizer.Token> tokens = SqlTokenizer.tokenize(createSql);
if (tokens == null) {
return null;
}
int open = -1;
for (int i = 0; i < tokens.size(); i++) {
if (tokens.get(i).isSymbol("(")) {
open = i;
break;
}
}
if (open < 0) {
return null;
}

List<List<SqlTokenizer.Token>> definitions = new ArrayList<>();
List<SqlTokenizer.Token> current = new ArrayList<>();
for (int i = open + 1; i < tokens.size(); i++) {
SqlTokenizer.Token token = tokens.get(i);
if (token.isSymbol(")") && token.depth() == 0) {
if (!current.isEmpty()) {
definitions.add(current);
}
return definitions;
}
if (token.isSymbol(",") && token.depth() == 1) {
definitions.add(current);
current = new ArrayList<>();
continue;
}
current.add(token);
}
return null;
}

private static boolean columnDefinitionIsAutoIncrement(
List<SqlTokenizer.Token> definition, String columnName) {
int start = skipConstraintName(definition);
if (start >= definition.size()) {
return false;
}
if (isConstraintKeyword(definition.get(start))) {
return false;
}
String name = definition.get(start).identifier();
if (name == null || !name.equalsIgnoreCase(columnName)) {
return false;
}
return containsKeyword(definition, start + 1, definition.size(), "AUTOINCREMENT", 1);
}

private static boolean tableConstraintIsAutoIncrement(
List<SqlTokenizer.Token> definition, String columnName) {
int start = skipConstraintName(definition);
if (start + 1 >= definition.size()
|| !definition.get(start).isWord("PRIMARY")
|| !definition.get(start + 1).isWord("KEY")) {
return false;
}
int open = -1;
for (int i = start + 2; i < definition.size(); i++) {
if (definition.get(i).isSymbol("(")) {
open = i;
break;
}
}
if (open < 0) {
return false;
}

int partStart = open + 1;
for (int i = open + 1; i < definition.size(); i++) {
SqlTokenizer.Token token = definition.get(i);
if ((token.isSymbol(",") && token.depth() == 2)
|| (token.isSymbol(")") && token.depth() == 1)) {
if (indexedColumnIsAutoIncrement(definition, partStart, i, columnName)) {
return true;
}
partStart = i + 1;
}
}
return false;
}

private static boolean indexedColumnIsAutoIncrement(
List<SqlTokenizer.Token> definition, int start, int end, String columnName) {
if (start >= end) {
return false;
}
String name = definition.get(start).identifier();
return name != null
&& name.equalsIgnoreCase(columnName)
&& containsKeyword(definition, start + 1, end, "AUTOINCREMENT", 2);
}

private static int skipConstraintName(List<SqlTokenizer.Token> definition) {
if (definition.size() >= 2 && definition.get(0).isWord("CONSTRAINT")) {
return 2;
}
return 0;
}

private static boolean isConstraintKeyword(SqlTokenizer.Token token) {
return token.isWord("PRIMARY")
|| token.isWord("UNIQUE")
|| token.isWord("CHECK")
|| token.isWord("FOREIGN");
}

private static boolean containsKeyword(
List<SqlTokenizer.Token> tokens, int start, int end, String keyword, int depth) {
for (int i = start; i < end; i++) {
SqlTokenizer.Token token = tokens.get(i);
if (token.depth() == depth && token.isWord(keyword)) {
return true;
}
}
return false;
}
}
Loading