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 @@ -762,7 +762,12 @@ private static String unescape(String content, char quote) {
}

private static boolean isWordChar(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$';
return c >= 0x80
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| c == '_'
|| c == '$';
}

private static String text(Value value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ static FromClause of(List<Source> sources) {
}
}

private static final Pattern UNQUOTED_IDENTIFIER = Pattern.compile("[A-Za-z_][A-Za-z0-9_$]*");
private static final Pattern UNQUOTED_IDENTIFIER =
Pattern.compile("[A-Za-z_\\x80-\\uFFFF][A-Za-z0-9_$\\x80-\\uFFFF]*");

private static final Set<String> FROM_END = Set.of(
"WHERE", "GROUP", "HAVING", "ORDER", "LIMIT", "OFFSET", "WINDOW", "RETURNING",
Expand Down Expand Up @@ -1273,6 +1274,11 @@ private static String unescape(String content, char quote) {
}

private static boolean isWordChar(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$';
return c >= 0x80
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| c == '_'
|| c == '$';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,30 @@ void resolvesTableNameNullabilityAndAutoIncrement() throws SQLException {
assertThat(metadata.isAutoIncrement(2)).isFalse();
}

@Test
void resolvesNonAsciiTableName() throws SQLException {
LibsqlResultSetMetaData metadata = new LibsqlResultSetMetaData(
List.of(new Col("namn_ö", "TEXT")),
List.of(),
"SELECT namn_ö FROM användare",
connectionForSwedishTables());

assertThat(metadata.getTableName(1)).isEqualTo("användare");
assertThat(metadata.isNullable(1)).isEqualTo(ResultSetMetaData.columnNullable);
}

@Test
void prefersNonAsciiTableOverItsAsciiPrefix() throws SQLException {
LibsqlResultSetMetaData metadata = new LibsqlResultSetMetaData(
List.of(new Col("namn_ö", "TEXT")),
List.of(),
"SELECT namn_ö FROM användare",
connectionForSwedishTables());

assertThat(metadata.getTableName(1)).isEqualTo("användare");
assertThat(metadata.getColumnName(1)).isEqualTo("namn_ö");
}

@Test
void ignoresAutoIncrementInsideSqlComments() throws SQLException {
String createSql = "CREATE TABLE People (id INTEGER PRIMARY KEY /* AUTOINCREMENT */, name TEXT)";
Expand Down Expand Up @@ -644,6 +668,33 @@ private static LibsqlResultSetMetaData metadataForTable(String createSql, List<C
return new LibsqlResultSetMetaData(cols, List.of(), "SELECT * FROM T", connectionReturning(result));
}

private static LibsqlConnection connectionForSwedishTables() {
Map<String, String> tables = Map.of(
"anv", "CREATE TABLE anv (id INTEGER)",
"användare", "CREATE TABLE användare (id INTEGER, namn_ö TEXT)");
Map<String, List<String>> columns = Map.of("anv", List.of("id"), "användare", List.of("id", "namn_ö"));
return new LibsqlConnection(null, null) {
@Override
public StmtResult executeStatement(Stmt stmt) throws SQLException {
String table = argument(stmt, 0);
String createSql = tables.get(table);
if (createSql == null) {
return new StmtResult(List.of(), List.of(), 0, null);
}
List<Row> rows = new ArrayList<>();
for (String column : columns.get(table)) {
rows.add(new Row(List.of(
Value.of(table),
Value.of(createSql),
Value.of(column),
Value.of(0L),
Value.of(0L))));
}
return new StmtResult(List.of(), rows, 0, null);
}
};
}

private static LibsqlConnection connectionReturning(StmtResult result) {
return new LibsqlConnection(null, null) {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ class SqlTableReferenceTest {
new SqlTableReference.TableDefinition("CREATE TABLE c (z TEXT)", List.of("z")),
"g",
new SqlTableReference.TableDefinition(
"CREATE TABLE g (p INTEGER, q AS (p+1), r TEXT NOT NULL)", List.of("p", "q", "r")));
"CREATE TABLE g (p INTEGER, q AS (p+1), r TEXT NOT NULL)", List.of("p", "q", "r")),
"anv",
new SqlTableReference.TableDefinition("CREATE TABLE anv (id INTEGER)", List.of("id")),
"användare",
new SqlTableReference.TableDefinition(
"CREATE TABLE användare (id INTEGER, namn_ö TEXT)", List.of("id", "namn_ö")));

private static final SqlTableReference.Schema SCHEMA = reference -> {
if (reference.table() == null) {
Expand Down Expand Up @@ -58,6 +63,57 @@ void resolvesQuotedAndBracketedNames() throws SQLException {
.containsExactly(new SqlTableReference.TableRef(null, "my table"));
}

@Test
void resolvesNonAsciiTableAndColumn() throws SQLException {
SqlTableReference.Resolution resolution = resolve("SELECT namn_ö FROM användare");

assertThat(resolution.labels()).containsExactly("namn_ö");
assertThat(resolution.tables())
.containsExactly(new SqlTableReference.TableRef(null, "användare"));
}

@Test
void resolvesNonAsciiColumnThroughTableAlias() throws SQLException {
assertThat(resolve("SELECT a.namn_ö FROM användare a").tables())
.containsExactly(new SqlTableReference.TableRef(null, "användare"));
assertThat(resolve("SELECT * FROM användare a").tables())
.containsExactly(
new SqlTableReference.TableRef(null, "användare"),
new SqlTableReference.TableRef(null, "användare"));
}

@Test
void resolvesNonAsciiAliases() throws SQLException {
assertThat(resolve("SELECT namn_ö AS namn FROM användare").labels()).containsExactly("namn");
assertThat(resolve("SELECT namn_ö namn FROM användare").labels()).containsExactly("namn");
assertThat(resolve("SELECT namn_ö AS namn FROM användare").tables())
.containsExactly(new SqlTableReference.TableRef(null, "användare"));
assertThat(resolve("SELECT å.namn_ö FROM användare AS å").tables())
.containsExactly(new SqlTableReference.TableRef(null, "användare"));
}

@Test
void resolvesQuotedNonAsciiNames() throws SQLException {
assertThat(resolve("SELECT namn_ö FROM \"användare\"").tables())
.containsExactly(new SqlTableReference.TableRef(null, "användare"));
assertThat(resolve("SELECT namn_ö FROM [användare]").tables())
.containsExactly(new SqlTableReference.TableRef(null, "användare"));
assertThat(resolve("SELECT \"namn_ö\" FROM \"användare\"").labels()).containsExactly("namn_ö");
}

@Test
void keepsNonAsciiTableWholeWhenAnAsciiPrefixTableExists() throws SQLException {
SqlTableReference.Resolution resolution = resolve("SELECT * FROM användare");

assertThat(resolution.labels()).containsExactly("id", "namn_ö");
assertThat(resolution.tables())
.containsExactly(
new SqlTableReference.TableRef(null, "användare"),
new SqlTableReference.TableRef(null, "användare"));
assertThat(resolve("SELECT id FROM anv").tables())
.containsExactly(new SqlTableReference.TableRef(null, "anv"));
}

@Test
void resolvesAliasesWithAndWithoutAs() throws SQLException {
assertThat(resolve("SELECT a AS z FROM w").labels()).containsExactly("z");
Expand Down
Loading