Skip to content
Closed
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 @@ -248,6 +248,14 @@ public String quoteIdentifier(String identifier) {
return identifier == null ? null : "`" + identifier + "`";
}

@Override
public String quoteIdentifierAlways(String identifier) {
if (identifier == null) {
return null;
}
return "`" + identifier.replace("`", "``") + "`";
}

@Override
public String removeIdentifierQuote(String identifier) {
return identifier == null ? null : identifier.replace("`", "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.List;

import static ai.chat2db.plugin.kingbase.constant.KingBaseIndexTypeEnumConstants.*;
import ai.chat2db.plugin.kingbase.KingBaseMetaData;
public enum KingBaseIndexTypeEnum {

PRIMARY("Primary", "PRIMARY KEY"),
Expand Down Expand Up @@ -92,10 +93,10 @@ private String buildForeignColum(TableIndex tableIndex) {
StringBuilder script = new StringBuilder();
script.append(" REFERENCES ");
if (StringUtils.isNotBlank(tableIndex.getForeignSchemaName())) {
script.append(tableIndex.getForeignSchemaName()).append(".");
script.append(KingBaseMetaData.KINGBASE_SQL_IDENTIFIER_PROCESSOR.quoteIdentifierAlways(tableIndex.getForeignSchemaName())).append(".");
}
if (StringUtils.isNotBlank(tableIndex.getForeignTableName())) {
script.append(tableIndex.getForeignTableName()).append(" ");
script.append(KingBaseMetaData.KINGBASE_SQL_IDENTIFIER_PROCESSOR.quoteIdentifierAlways(tableIndex.getForeignTableName())).append(" ");
}
if (CollectionUtils.isNotEmpty(tableIndex.getForeignColumnNamelist())) {
script.append("(");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,26 @@ public String quoteIdentifier(String identifier) {
return "`" + identifier + "`";
}

@Override
public String quoteIdentifierAlways(String identifier) {
if (identifier == null) {
return null;
}
return "`" + identifier.replace("`", "``") + "`";
}

@Override
public String removeIdentifierQuote(String identifier) {
if (StringUtils.isBlank(identifier)) {
return identifier;
}
return removePattern(identifier, MYSQL_PATTERN);
if (identifier.startsWith("`") && identifier.endsWith("`") && identifier.length() >= 2) {
return identifier.substring(1, identifier.length() - 1).replace("``", "`");
}
if (identifier.startsWith("\"") && identifier.endsWith("\"") && identifier.length() >= 2) {
return identifier.substring(1, identifier.length() - 1).replace("\"\"", "\"");
}
return identifier;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package ai.chat2db.plugin.mysql.identifier;

import ai.chat2db.spi.DefaultSQLIdentifierProcessor;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

/**
* Contract tests for {@link MysqlIdentifierProcessor}.
* Covers the backtick-based {@code quoteIdentifierAlways} /
* {@code removeIdentifierQuote} round-trip and embedded-delimiter escaping.
*/
class MysqlIdentifierProcessorTest {

private final MysqlIdentifierProcessor processor = new MysqlIdentifierProcessor();

@Test
void quoteIdentifierAlways_wrapsInBacktick() {
assertEquals("`mycol`", processor.quoteIdentifierAlways("mycol"));
}

@Test
void quoteIdentifierAlways_escapesEmbeddedBacktick() {
assertEquals("`a``b`", processor.quoteIdentifierAlways("a`b"));
}

@Test
void quoteIdentifierAlways_preservesMixedCase() {
assertEquals("`MixedCase`", processor.quoteIdentifierAlways("MixedCase"));
}

@Test
void quoteIdentifierAlways_handlesNull() {
assertNull(processor.quoteIdentifierAlways(null));
}

@Test
void removeIdentifierQuote_stripsBacktick() {
assertEquals("mycol", processor.removeIdentifierQuote("`mycol`"));
}

@Test
void removeIdentifierQuote_unescapesBacktick() {
assertEquals("a`b", processor.removeIdentifierQuote("`a``b`"));
}

@Test
void removeIdentifierQuote_stripsDoubleQuote() {
assertEquals("mycol", processor.removeIdentifierQuote("\"mycol\""));
}

@Test
void roundTrip_plainName() {
String raw = "mycol";
assertEquals(raw, processor.removeIdentifierQuote(processor.quoteIdentifierAlways(raw)));
}

@Test
void roundTrip_embeddedBacktick() {
String raw = "a`b";
assertEquals(raw, processor.removeIdentifierQuote(processor.quoteIdentifierAlways(raw)));
}

@Test
void roundTrip_mixedCase() {
String raw = "MixedCase";
assertEquals(raw, processor.removeIdentifierQuote(processor.quoteIdentifierAlways(raw)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.List;

import static ai.chat2db.plugin.postgresql.constant.PostgreSQLIndexTypeEnumConstants.*;
import ai.chat2db.plugin.postgresql.PostgreSQLMetaData;
public enum PostgreSQLIndexTypeEnum {

PRIMARY("Primary", "PRIMARY KEY"),
Expand Down Expand Up @@ -92,10 +93,10 @@ private String buildForeignColum(TableIndex tableIndex) {
StringBuilder script = new StringBuilder();
script.append(" REFERENCES ");
if (StringUtils.isNotBlank(tableIndex.getForeignSchemaName())) {
script.append(tableIndex.getForeignSchemaName()).append(".");
script.append(PostgreSQLMetaData.POSTGRE_SQL_IDENTIFIER_PROCESSOR.quoteIdentifierAlways(tableIndex.getForeignSchemaName())).append(".");
}
if (StringUtils.isNotBlank(tableIndex.getForeignTableName())) {
script.append(tableIndex.getForeignTableName()).append(" ");
script.append(PostgreSQLMetaData.POSTGRE_SQL_IDENTIFIER_PROCESSOR.quoteIdentifierAlways(tableIndex.getForeignTableName())).append(" ");
}
if (CollectionUtils.isNotEmpty(tableIndex.getForeignColumnNamelist())) {
script.append("(");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import ai.chat2db.plugin.snowflake.builder.SnowflakeSqlBuilder;
import ai.chat2db.plugin.snowflake.enums.type.*;
import ai.chat2db.spi.IDbMetaData;
import ai.chat2db.spi.DefaultSQLIdentifierProcessor;
import ai.chat2db.spi.ISQLIdentifierProcessor;
import ai.chat2db.spi.ISqlBuilder;
import ai.chat2db.spi.DefaultMetaService;
import ai.chat2db.community.domain.api.model.account.*;
Expand All @@ -29,6 +31,8 @@
import static ai.chat2db.plugin.snowflake.constant.SnowflakeMetaDataConstants.*;
public class SnowflakeMetaData extends DefaultMetaService implements IDbMetaData {

public static final ISQLIdentifierProcessor SNOWFLAKE_SQL_IDENTIFIER_PROCESSOR = new DefaultSQLIdentifierProcessor();



@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,26 @@ public String quoteIdentifier(String identifier) {
return "[" + identifier + "]";
}

@Override
public String quoteIdentifierAlways(String identifier) {
if (identifier == null) {
return null;
}
return "[" + identifier.replace("]", "]]") + "]";
}

@Override
public String removeIdentifierQuote(String identifier) {
if (StringUtils.isBlank(identifier)) {
return identifier;
}
return removePattern(identifier, SQL_SERVER_PATTERN);
if (identifier.startsWith("[") && identifier.endsWith("]") && identifier.length() >= 2) {
return identifier.substring(1, identifier.length() - 1).replace("]]", "]");
}
if (identifier.startsWith("\"") && identifier.endsWith("\"") && identifier.length() >= 2) {
return identifier.substring(1, identifier.length() - 1).replace("\"\"", "\"");
}
return identifier;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ai.chat2db.plugin.sqlserver.identifier;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

/**
* Contract tests for {@link SqlServerIdentifierProcessor}.
* Covers the bracket-based {@code quoteIdentifierAlways} /
* {@code removeIdentifierQuote} round-trip and embedded-delimiter escaping.
*/
class SqlServerIdentifierProcessorTest {

private final SqlServerIdentifierProcessor processor = new SqlServerIdentifierProcessor();

@Test
void quoteIdentifierAlways_wrapsInBrackets() {
assertEquals("[mycol]", processor.quoteIdentifierAlways("mycol"));
}

@Test
void quoteIdentifierAlways_preservesMixedCase() {
assertEquals("[MixedCase]", processor.quoteIdentifierAlways("MixedCase"));
}

@Test
void quoteIdentifierAlways_escapesEmbeddedCloseBracket() {
assertEquals("[a]]b]", processor.quoteIdentifierAlways("a]b"));
}

@Test
void quoteIdentifierAlways_handlesNull() {
assertNull(processor.quoteIdentifierAlways(null));
}

@Test
void removeIdentifierQuote_stripsBrackets() {
assertEquals("mycol", processor.removeIdentifierQuote("[mycol]"));
}

@Test
void removeIdentifierQuote_unescapesCloseBracket() {
assertEquals("a]b", processor.removeIdentifierQuote("[a]]b]"));
}

@Test
void removeIdentifierQuote_stripsDoubleQuote() {
assertEquals("mycol", processor.removeIdentifierQuote("\"mycol\""));
}

@Test
void roundTrip_plainName() {
String raw = "mycol";
assertEquals(raw, processor.removeIdentifierQuote(processor.quoteIdentifierAlways(raw)));
}

@Test
void roundTrip_embeddedCloseBracket() {
String raw = "a]b";
assertEquals(raw, processor.removeIdentifierQuote(processor.quoteIdentifierAlways(raw)));
}

@Test
void roundTrip_mixedCase() {
String raw = "MixedCase";
assertEquals(raw, processor.removeIdentifierQuote(processor.quoteIdentifierAlways(raw)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,23 @@ public String quoteIdentifier(String identifier) {
return StringUtils.wrap(identifier, '"');
}

@Override
public String quoteIdentifierAlways(String identifier) {
if (identifier == null) {
return null;
}
return "\"" + identifier.replace("\"", "\"\"") + "\"";
}

@Override
public String removeIdentifierQuote(String identifier) {
if (StringUtils.isBlank(identifier)) {
return identifier;
}
return removePattern(identifier, STANDARD_PATTERN);
if (identifier.startsWith("\"") && identifier.endsWith("\"") && identifier.length() >= 2) {
return identifier.substring(1, identifier.length() - 1).replace("\"\"", "\"");
}
return identifier;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,16 @@ public interface ISQLIdentifierProcessor {
*/
String escapeString(String str);


/**
* Quotes an identifier unconditionally, preserving the exact name.
* <p>
* Embedded delimiter characters are escaped per the dialect convention.
* Satisfies: {@code removeIdentifierQuote(quoteIdentifierAlways(raw)).equals(raw)}
*
* @param identifier raw identifier text.
* @return unconditionally quoted identifier text with the original case preserved.
*/
String quoteIdentifierAlways(String identifier);

}
Loading
Loading