mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-13 08:30:45 +00:00
8143165: Add Statement.isSimpleIdentifier and update enquoteLiteral
Reviewed-by: rriggs, joehw
This commit is contained in:
parent
063afcee2f
commit
0c8069758d
@ -1397,9 +1397,10 @@ public interface Statement extends Wrapper, AutoCloseable {
|
||||
* @param val a character string
|
||||
* @return A string enclosed by single quotes with every single quote
|
||||
* converted to two single quotes
|
||||
* @throws NullPointerException if val is null
|
||||
* @throws NullPointerException if val is {@code null}
|
||||
* @throws SQLException if a database access error occurs
|
||||
*/
|
||||
default String enquoteLiteral(String val) {
|
||||
default String enquoteLiteral(String val) throws SQLException {
|
||||
return "'" + val.replace("'", "''") + "'";
|
||||
}
|
||||
|
||||
@ -1437,7 +1438,7 @@ public interface Statement extends Wrapper, AutoCloseable {
|
||||
*
|
||||
* The default implementation will throw a {@code SQLException} if:
|
||||
* <ul>
|
||||
* <li>{@code identifier} contains a null character or double quote, and is not
|
||||
* <li>{@code identifier} contains a {@code null} character or double quote and is not
|
||||
* a simple SQL identifier.</li>
|
||||
* <li>The length of {@code identifier} is less than 1 or greater than 128 characters
|
||||
* </ul>
|
||||
@ -1501,14 +1502,14 @@ public interface Statement extends Wrapper, AutoCloseable {
|
||||
* @throws SQLException if identifier is not a valid identifier
|
||||
* @throws SQLFeatureNotSupportedException if the datasource does not support
|
||||
* delimited identifiers
|
||||
* @throws NullPointerException if identifier is null
|
||||
* @throws NullPointerException if identifier is {@code null}
|
||||
*/
|
||||
default String enquoteIdentifier(String identifier, boolean alwaysQuote) throws SQLException {
|
||||
int len = identifier.length();
|
||||
if (len < 1 || len > 128) {
|
||||
throw new SQLException("Invalid name");
|
||||
}
|
||||
if (Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]+").matcher(identifier).matches()) {
|
||||
if (Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches()) {
|
||||
return alwaysQuote ? "\"" + identifier + "\"" : identifier;
|
||||
}
|
||||
if (identifier.matches("^\".+\"$")) {
|
||||
@ -1520,4 +1521,65 @@ public interface Statement extends Wrapper, AutoCloseable {
|
||||
throw new SQLException("Invalid name");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves whether {@code identifier} is a simple SQL identifier.
|
||||
*
|
||||
* @implSpec The default implementation uses the following criteria to
|
||||
* determine a valid simple SQL identifier:
|
||||
* <ul>
|
||||
* <li>The string is not enclosed in double quotes</li>
|
||||
* <li>The first character is an alphabetic character from a through z, or
|
||||
* from A through Z</li>
|
||||
* <li>The string only contains alphanumeric characters or the character
|
||||
* "_"</li>
|
||||
* <li>The string is between 1 and 128 characters in length inclusive</li>
|
||||
* </ul>
|
||||
*
|
||||
* <blockquote>
|
||||
* <table border = 1 cellspacing=0 cellpadding=5 >
|
||||
* <caption>Examples of the conversion:</caption>
|
||||
* <tr>
|
||||
* <th>identifier</th>
|
||||
* <th>Simple Identifier</th>
|
||||
*
|
||||
* <tr>
|
||||
* <td align='center'>Hello</td>
|
||||
* <td align='center'>true</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align='center'>G'Day</td>
|
||||
* <td align='center'>false</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align='center'>"Bruce Wayne"</td>
|
||||
* <td align='center'>false</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align='center'>GoodDay$</td>
|
||||
* <td align='center'>false</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align='center'>Hello"World</td>
|
||||
* <td align='center'>false</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align='center'>"Hello"World"</td>
|
||||
* <td align='center'>false</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* </blockquote>
|
||||
* @implNote JDBC driver implementations may need to provide their own
|
||||
* implementation of this method in order to meet the requirements of the
|
||||
* underlying datasource.
|
||||
* @param identifier a SQL identifier
|
||||
* @return true if a simple SQL identifier, false otherwise
|
||||
* @throws NullPointerException if identifier is {@code null}
|
||||
* @throws SQLException if a database access error occurs
|
||||
*/
|
||||
default boolean isSimpleIdentifier(String identifier) throws SQLException {
|
||||
int len = identifier.length();
|
||||
return len >= 1 && len <= 128
|
||||
&& Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches();
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ package test.sql;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
@ -33,18 +34,29 @@ import util.StubStatement;
|
||||
public class StatementTests extends BaseTest {
|
||||
|
||||
protected StubStatement stmt;
|
||||
protected static String maxIdentifier;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUpMethod() throws Exception {
|
||||
stmt = new StubStatement();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
int maxLen = 128;
|
||||
StringBuilder s = new StringBuilder(maxLen);
|
||||
for (int i = 0; i < maxLen; i++) {
|
||||
s.append('a');
|
||||
}
|
||||
maxIdentifier = s.toString();
|
||||
}
|
||||
/*
|
||||
* Verify that enquoteLiteral creates a valid literal and converts every
|
||||
* single quote to two single quotes
|
||||
*/
|
||||
|
||||
@Test(dataProvider = "validEnquotedLiteralValues")
|
||||
public void test00(String s, String expected) {
|
||||
public void test00(String s, String expected) throws SQLException {
|
||||
assertEquals(stmt.enquoteLiteral(s), expected);
|
||||
}
|
||||
|
||||
@ -53,7 +65,7 @@ public class StatementTests extends BaseTest {
|
||||
* enquoteLiteral is null
|
||||
*/
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void test01() {
|
||||
public void test01() throws SQLException {
|
||||
stmt.enquoteLiteral(null);
|
||||
|
||||
}
|
||||
@ -89,6 +101,24 @@ public class StatementTests extends BaseTest {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that isSimpleIdentifier returns the expected value
|
||||
*/
|
||||
@Test(dataProvider = "simpleIdentifierValues")
|
||||
public void test05(String s, boolean expected) throws SQLException {
|
||||
assertEquals(stmt.isSimpleIdentifier(s), expected);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate a NullPointerException is thrown is the string passed to
|
||||
* isSimpleIdentifier is null
|
||||
*/
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void test06() throws SQLException {
|
||||
stmt.isSimpleIdentifier(null);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* DataProvider used to provide strings that will be used to validate
|
||||
* that enquoteLiteral converts a string to a literal and every instance of
|
||||
@ -114,6 +144,10 @@ public class StatementTests extends BaseTest {
|
||||
@DataProvider(name = "validIdentifierValues")
|
||||
protected Object[][] validEnquotedIdentifierValues() {
|
||||
return new Object[][]{
|
||||
{"b", false, "b"},
|
||||
{"b", true, "\"b\""},
|
||||
{maxIdentifier, false, maxIdentifier},
|
||||
{maxIdentifier, true, "\"" + maxIdentifier + "\""},
|
||||
{"Hello", false, "Hello"},
|
||||
{"Hello", true, "\"Hello\""},
|
||||
{"G'Day", false, "\"G'Day\""},
|
||||
@ -130,16 +164,34 @@ public class StatementTests extends BaseTest {
|
||||
*/
|
||||
@DataProvider(name = "invalidIdentifierValues")
|
||||
protected Object[][] invalidEnquotedIdentifierValues() {
|
||||
int invalidLen = 129;
|
||||
StringBuilder s = new StringBuilder(invalidLen);
|
||||
for (int i = 0; i < invalidLen; i++) {
|
||||
s.append('a');
|
||||
}
|
||||
return new Object[][]{
|
||||
{"Hel\"lo", false},
|
||||
{"\"Hel\"lo\"", true},
|
||||
{"Hello" + '\0', false},
|
||||
{"", false},
|
||||
{s.toString(), false},};
|
||||
{maxIdentifier + 'a', false},
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* DataProvider used to provide strings that will be used to validate
|
||||
* that isSimpleIdentifier returns the correct value based on the
|
||||
* identifier specified.
|
||||
*/
|
||||
@DataProvider(name = "simpleIdentifierValues")
|
||||
protected Object[][] simpleIdentifierValues() {
|
||||
return new Object[][]{
|
||||
{"b", true},
|
||||
{"Hello", true},
|
||||
{"\"Gotham\"", false},
|
||||
{"G'Day", false},
|
||||
{"Bruce Wayne", false},
|
||||
{"GoodDay$", false},
|
||||
{"Dick_Grayson", true},
|
||||
{"Batmobile1966", true},
|
||||
{maxIdentifier, true},
|
||||
{maxIdentifier + 'a', false},
|
||||
{"", false},};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user