From cfd99c7f3ec9fe846f36840422ae41d2f8f60111 Mon Sep 17 00:00:00 2001 From: rusher Date: Thu, 6 Jun 2019 15:36:05 +0200 Subject: [PATCH 01/19] [MENT-28] azure pipelines testing implementation --- azure-pipelines.yml | 191 ++++++++++++++++++ .../org/mariadb/jdbc/MariaDbConnection.java | 2 +- .../protocol/AbstractQueryProtocol.java | 2 +- src/test/java/org/mariadb/jdbc/BaseTest.java | 12 ++ .../java/org/mariadb/jdbc/ConnectionTest.java | 17 +- .../java/org/mariadb/jdbc/DriverTest.java | 31 ++- .../jdbc/LocalInfileInputStreamTest.java | 40 +++- .../mariadb/jdbc/PasswordEncodingTest.java | 2 +- .../java/org/mariadb/jdbc/StatementTest.java | 6 +- .../java/org/mariadb/jdbc/TimeoutTest.java | 2 +- 10 files changed, 274 insertions(+), 31 deletions(-) create mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 000000000..91c046ab9 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,191 @@ +resources: + containers: + + - container: ubuntu-1604 + image: ubuntu:16.04 + options: "--name ubuntu-1604 --add-host=mariadb.example.com:127.0.0.1 -v /usr/bin/docker:/tmp/docker:ro" + + - container: ubuntu-1804 + image: ubuntu:18.04 + options: "--name ubuntu-1804 --add-host=mariadb.example.com:127.0.0.1 -v /usr/bin/docker:/tmp/docker:ro" + +jobs: + + - job: SSLFiles + displayName: 'Creating SSL Files' + pool: + vmImage: 'ubuntu-16.04' + container: $[ variables['containerImage'] ] + steps: + - script: | + java --version + mkdir tmp + .travis/gen-ssl.sh mariadb.example.com tmp + ls -lrt tmp + cp -R tmp $BUILD_ARTIFACTSTAGINGDIRECTORY + displayName: 'create SSL certificates' + + - task: PublishPipelineArtifact@0 + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)' + artifactName: ssl_certs + + - job: windowsTest + displayName: 'test windows' + pool: + vmImage: 'win1803' + dependsOn: + - SSLFiles + steps: + - task: DownloadPipelineArtifact@0 + inputs: + artifactName: ssl_certs + targetPath: $(System.DefaultWorkingDirectory) + + - task: DownloadPipelineArtifact@1 + displayName: 'Download server artifact files' + inputs: + buildType: 'specific' + project: 'test mariadb ent' + pipeline: 'rusher.MariaDBEnterprise' + artifactName: Windows + #buildVersionToDownload: 'latest' + buildId: 73 + buildVersionToDownload: 'specific' + downloadPath: $(System.DefaultWorkingDirectory) + - script: | + choco install jdk8 -ia "INSTALLDIR=""c:\java""" + type C:\ProgramData\chocolatey\logs\chocolatey.log + Get-EnvironmentVariable -Name 'JAVA_HOME' -Scope 'Machine' + choco install maven + echo %PATH% + echo %JAVA_HOME% + refreshenv + echo %PATH% + echo %JAVA_HOME% + displayName: 'install java + maven' + + - script: | + msiexec /i $(System.DefaultWorkingDirectory)\win_build\win\packaging\mariadb-10.4.5-winx64.msi INSTALLDIR=c:\projects\server SERVICENAME=mariadb ALLOWREMOTEROOTACCESS=true /qn + c:\projects\server\bin\mysql.exe -e "create database testj" --user=root + displayName: 'install server' + + - script: | + echo 127.0.0.1 mariadb.example.com >> %WINDIR%\System32\Drivers\Etc\Hosts + dir + displayName: 'set hostname' + + - script: | + set JAVA_HOME=C:\java\ + set PATH=%PATH%;%JAVA_HOME%\bin + java -version + C:\ProgramData\chocolatey\bin\mvn -version + C:\ProgramData\chocolatey\bin\mvn clean test -DdbUrl="jdbc:mariadb://mariadb.example.com:3306/testj?user=root" -DkeystorePath="$(System.DefaultWorkingDirectory)/tmp/client-keystore.jks" -DkeystorePassword="kspass" -DserverCertificatePath="$(System.DefaultWorkingDirectory)/tmp/server.crt" -Dkeystore2Path="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.jks" -Dkeystore2Password="kspass" -DkeyPassword="kspasskey" -Dkeystore2PathP12="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.p12" -DrunLongTest=false + displayName: 'run tests' + + + - job: RunInContainer + pool: + vmImage: 'ubuntu-16.04' + dependsOn: + - SSLFiles + strategy: + matrix: + ubuntu-1604: + containerImage: ubuntu-1604 + containerName: xenial + ubuntu-1804: + containerImage: ubuntu-1804 + containerName: bionic + + container: $[variables['containerImage']] + + steps: + + - task: DownloadPipelineArtifact@0 + inputs: + artifactName: ssl_certs + targetPath: $(System.DefaultWorkingDirectory) + + - script: /tmp/docker exec -t -u 0 $(containerImage) sh -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" -y install sudo" + displayName: Set up sudo + + - task: DownloadPipelineArtifact@1 + displayName: 'Download server artifact files' + inputs: + buildType: 'specific' + project: 'test mariadb ent' + pipeline: 'rusher.MariaDBEnterprise' + artifactName: $(containerImage) + #buildVersionToDownload: 'latest' + buildId: 47 + buildVersionToDownload: 'specific' + downloadPath: $(System.DefaultWorkingDirectory) + + - script: | + sudo apt-get install -y software-properties-common wget + wget -qO- 'https://github.com/tianon/pgp-happy-eyeballs/raw/master/hack-my-builds.sh' | bash + sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db + sudo apt-key adv --recv-keys --keyserver ha.pool.sks-keyservers.net F1656F24C74CD1D8 + displayName: 'Add galera signature keys' + + - script: | + sudo bash -c "echo 'deb http://yum.mariadb.org/galera/repo/deb xenial main' > /etc/apt/sources.list.d/galera-test-repo.list" + condition: eq(variables['containerImage'], 'ubuntu-1604') + displayName: 'Add xenial galera repo' + + - script: | + sudo bash -c "echo 'deb http://yum.mariadb.org/galera/repo/deb bionic main' > /etc/apt/sources.list.d/galera-test-repo.list" + condition: eq(variables['containerImage'], 'ubuntu-1804') + displayName: 'Add bionic galera repo' + + - script: | + ls -lrt . + echo "Installing server from deb" + sudo ln -fs /usr/share/zoneinfo/UTC /etc/localtime + rm -R mariadb-plugin* + rm -R *-dev.deb + rm -R *-test.deb + chmod 777 . + + sudo apt-get update && sudo apt-get install -y --no-install-recommends apt-transport-https ca-certificates tzdata pwgen + export DEBIAN_FRONTEND="noninteractive" + sudo debconf-set-selections <<< "mariadb-server-10.4 mysql-server/root_password password !Passw0rd" + sudo debconf-set-selections <<< "mariadb-server-10.4 mysql-server/root_password_again password !Passw0rd" + sudo apt-get update -y + + sudo apt-get install --allow-unauthenticated -y curl libdbi-perl rsync socat libnuma1 libaio1 zlib1g-dev libreadline5 libjemalloc1 libsnappy1v5 libcrack2 galera-4 gawk lsof psmisc libaio1 perl libreadline5 + + echo 'Installing deb files' + sudo apt install -f -y ./*.deb + + sudo ls -lrt /etc/mysql/ + sudo bash -c 'echo "ssl-ca=$(System.DefaultWorkingDirectory)/tmp/ca.crt" >> /etc/mysql/mariadb-enterprise.cnf' + sudo bash -c 'echo "ssl-cert=$(System.DefaultWorkingDirectory)/tmp/server.crt" >> /etc/mysql/mariadb-enterprise.cnf' + sudo bash -c 'echo "ssl-key=$(System.DefaultWorkingDirectory)/tmp/server.key" >> /etc/mysql/mariadb-enterprise.cnf' + sudo tail -n 500 /etc/mysql/mariadb-enterprise.cnf + + sudo service mysql restart + + displayName: 'install server' + + - script: | + sudo mysql -e "CREATE USER 'root'@'%' identified by 'Passw@rd2';" + sudo mysql -e "GRANT ALL on *.* to 'root'@'%' identified by 'Passw@rd2' with grant option;" + sudo mysql -e "CREATE DATABASE testj;" + displayName: 'Add non socket user' + + - script: | + sudo apt install -y default-jdk + sudo apt install -y maven + mvn -version + java -version + displayName: 'Install java + maven' + + - script: | + ls -lrt /usr/share/maven/bin/ + /usr/share/maven/bin/mvn clean test -DdbUrl="jdbc:mariadb://mariadb.example.com:3306/testj?user=root&password=Passw@rd2" -DkeystorePath="$(System.DefaultWorkingDirectory)/tmp/client-keystore.jks" -DkeystorePassword="kspass" -DserverCertificatePath="$(System.DefaultWorkingDirectory)/tmp/server.crt" -Dkeystore2Path="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.jks" -Dkeystore2Password="kspass" -DkeyPassword="kspasskey" -Dkeystore2PathP12="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.p12" -DrunLongTest=false + env: + JAVA_HOME: "/usr/lib/jvm/default-java" + MAVEN_HOME: "/opt/maven" + displayName: 'run tests' \ No newline at end of file diff --git a/src/main/java/org/mariadb/jdbc/MariaDbConnection.java b/src/main/java/org/mariadb/jdbc/MariaDbConnection.java index fdd1060bb..ce386e062 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbConnection.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbConnection.java @@ -256,7 +256,7 @@ public Statement createStatement(final int resultSetType, final int resultSetCon private void checkConnection() throws SQLException { if (protocol.isExplicitClosed()) { - throw new SQLException("createStatement() is called on closed connection"); + throw new SQLNonTransientConnectionException("createStatement() is called on closed connection"); } if (protocol.isClosed() && protocol.getProxy() != null) { lock.lock(); diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java index 661616002..48e53ecc3 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractQueryProtocol.java @@ -1768,7 +1768,7 @@ public void prolog(long maxRows, boolean hasProxy, MariaDbConnection connection, MariaDbStatement statement) throws SQLException { if (explicitClosed) { - throw new SQLException("execute() is called on closed connection"); + throw new SQLNonTransientConnectionException("execute() is called on closed connection"); } //old failover handling if (!hasProxy && shouldReconnectWithoutProxy()) { diff --git a/src/test/java/org/mariadb/jdbc/BaseTest.java b/src/test/java/org/mariadb/jdbc/BaseTest.java index 80f2865bb..890e13f56 100644 --- a/src/test/java/org/mariadb/jdbc/BaseTest.java +++ b/src/test/java/org/mariadb/jdbc/BaseTest.java @@ -68,6 +68,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.SQLNonTransientConnectionException; import java.sql.Statement; import java.text.DecimalFormat; import java.text.NumberFormat; @@ -144,6 +145,17 @@ protected void finished(Description description) { ResultSet rs = preparedStatement.executeQuery(); assertTrue(rs.next()); assertEquals(randInt, rs.getInt(1)); + } catch (SQLNonTransientConnectionException connFail) { + connFail.printStackTrace(); + try { + beforeClassBaseTest(); + } catch (SQLException e) { + System.out.println("ERROR reconnecting"); + e.printStackTrace(); + } + fail("Prepare after test fail for " + description.getClassName() + "." + description + .getMethodName()); + } catch (Exception e) { e.printStackTrace(); fail("Prepare after test fail for " + description.getClassName() + "." + description diff --git a/src/test/java/org/mariadb/jdbc/ConnectionTest.java b/src/test/java/org/mariadb/jdbc/ConnectionTest.java index 8966d29f6..fb23c9a75 100644 --- a/src/test/java/org/mariadb/jdbc/ConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/ConnectionTest.java @@ -257,6 +257,8 @@ public void checkMaxAllowedPacket() throws Throwable { assertTrue(rs.next()); int maxAllowedPacket = rs.getInt(2); + Assume.assumeTrue(maxAllowedPacket < 40_000_000); + //Create a SQL stream bigger than maxAllowedPacket StringBuilder sb = new StringBuilder(); String rowData = "('this is a dummy row values')"; @@ -508,7 +510,7 @@ public void run() { delayProxy(1500); long start = System.currentTimeMillis(); assertFalse(connection.isValid(1)); //1 second - assertTrue(System.currentTimeMillis() - start < 1050); + assertTrue(System.currentTimeMillis() - start < 1250); Thread.sleep(5000); } finally { closeProxy(); @@ -589,14 +591,14 @@ public void verificationEd25519AuthPlugin() throws Throwable { } try { stmt.execute("CREATE USER verificationEd25519AuthPlugin@'%' IDENTIFIED " - + "VIA ed25519 USING 'ZIgUREUg5PVgQ6LskhXmO+eZLS0nC8be6HPjYWR4YJY'"); + + "VIA ed25519 USING 'Dl7wP5om2lNrAfxWw3ooyZKDAoBztFNuhtVFdIrWfi0'"); } catch (SQLException sqle) { //already existing } stmt.execute("GRANT ALL on " + database + ".* to verificationEd25519AuthPlugin@'%'"); String url = "jdbc:mariadb://" + hostname + ((port == 0) ? "" : ":" + port) + "/" + database - + "?user=verificationEd25519AuthPlugin&password=secret&debug=true"; + + "?user=verificationEd25519AuthPlugin&password=!Passw0rd3&debug=true"; try (Connection connection = openNewConnection(url)) { //must have succeed @@ -692,9 +694,8 @@ public void multiAuthPlugin() throws Throwable { stmt.execute("drop user IF EXISTS mysqltest1@'%'"); try { stmt.execute("CREATE USER mysqltest1@'%' IDENTIFIED " - + "VIA mysql_old_password USING '021bec665bf663f1' " - + " OR ed25519 as password('good') " - + " OR mysql_native_password as password('works')"); + + "VIA ed25519 as password('!Passw0rd3') " + + " OR mysql_native_password as password('!Passw0rd3Works')"); } catch (SQLException sqle) { //already existing sqle.printStackTrace(); @@ -703,13 +704,13 @@ public void multiAuthPlugin() throws Throwable { try (Connection connection = openNewConnection( "jdbc:mariadb://" + hostname + ((port == 0) ? "" : ":" + port) + "/" + database - + "?user=mysqltest1&password=good")) { + + "?user=mysqltest1&password=!Passw0rd3")) { //must have succeed } try (Connection connection = openNewConnection( "jdbc:mariadb://" + hostname + ((port == 0) ? "" : ":" + port) + "/" + database - + "?user=mysqltest1&password=works")) { + + "?user=mysqltest1&password=!Passw0rd3Works")) { //must have succeed } diff --git a/src/test/java/org/mariadb/jdbc/DriverTest.java b/src/test/java/org/mariadb/jdbc/DriverTest.java index 7e5b9738f..54cecbe89 100644 --- a/src/test/java/org/mariadb/jdbc/DriverTest.java +++ b/src/test/java/org/mariadb/jdbc/DriverTest.java @@ -1420,7 +1420,7 @@ public void namedPipeWithoutHost() { @Test public void localSocket() throws Exception { requireMinimumVersion(5, 1); - Assume.assumeTrue(System.getenv("TRAVIS") == null); + Assume.assumeTrue(System.getenv("TRAVIS") == null && System.getenv("DOCKER_SOCKET") == null); Assume.assumeTrue(isLocalConnection("localSocket")); Statement st = sharedConnection.createStatement(); @@ -1435,10 +1435,21 @@ public void localSocket() throws Exception { } String path = rs.getString(2); - try (Connection connection = setConnection("&localSocket=" + path + "&profileSql=true")) { + + st.execute("CREATE USER testSocket@'\" + ((hostname == null) ? \"localhost\" : hostname) +\"' IDENTIFIED VIA unix_socket"); + try { + st.execute("INSTALL SONAME 'auth_socket'"); + } catch (SQLException e) { + //dismiss, can already be installed + } + + String connString = connU + "?user=testSocket&localSocket=" + path + "&profileSql=true"; + System.out.println(connString); + try (Connection connection = openConnection(connString, null)) { rs = connection.createStatement().executeQuery("select 1"); assertTrue(rs.next()); } + st.execute("DROP user testSocket@'" + ((hostname == null) ? "localhost" : hostname) +"'"); } @Test @@ -1456,13 +1467,17 @@ public void sharedMemory() throws Exception { return; // skip test on non-Windows } - rs = st.executeQuery("select @@shared_memory,@@shared_memory_base_name"); - if (!rs.next()) { - return; - } + try { + rs = st.executeQuery("select @@shared_memory,@@shared_memory_base_name"); + if (!rs.next()) { + return; + } - if (!rs.getString(1).equals("1")) { - return; + if (!rs.getString(1).equals("1")) { + return; + } + } catch (SQLException e) { + return; } String shmBaseName = rs.getString(2); diff --git a/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java b/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java index aab3919c5..e25da45d5 100644 --- a/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalInfileInputStreamTest.java @@ -92,18 +92,20 @@ public static void initClass() throws SQLException { @Test public void testLocalInfileInputStream() throws SQLException { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 3)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); try (Connection connection = setConnection("&allowLocalInfile=true")) { try (Statement st = connection.createStatement()) { // Build a tab-separated record file String builder = "1\thello\n" - + "2\tworld\n"; + + "2\tworld\n"; InputStream inputStream = new ByteArrayInputStream(builder.getBytes()); ((MariaDbStatement) st).setLocalInfileInputStream(inputStream); st.executeUpdate( - "LOAD DATA LOCAL INFILE 'dummy.tsv' INTO TABLE LocalInfileInputStreamTest (id, test)"); + "LOAD DATA LOCAL INFILE 'dummy.tsv' INTO TABLE LocalInfileInputStreamTest (id, test)"); ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM LocalInfileInputStreamTest"); assertTrue(rs.next()); @@ -121,7 +123,9 @@ public void testLocalInfileInputStream() throws SQLException { @Test public void testLocalInfileValidInterceptor() throws Exception { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 3)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); File temp = File.createTempFile("validateInfile", ".txt"); StringBuilder builder = new StringBuilder(); builder.append("1,hello\n"); @@ -136,7 +140,9 @@ public void testLocalInfileValidInterceptor() throws Exception { @Test public void testLocalInfileUnValidInterceptor() throws Exception { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 3)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); File temp = File.createTempFile("localInfile", ".txt"); StringBuilder builder = new StringBuilder(); builder.append("1,hello\n"); @@ -184,7 +190,9 @@ private void testLocalInfile(Connection connection, String file) throws SQLExcep @SuppressWarnings("ResultOfMethodCallIgnored") @Test public void loadDataInfileEmpty() throws SQLException, IOException { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 3)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); // Create temp file. File temp = File.createTempFile("validateInfile", ".tmp"); try (Connection connection = setConnection("&allowLocalInfile=true")) { @@ -201,7 +209,10 @@ public void loadDataInfileEmpty() throws SQLException, IOException { @Test public void testPrepareLocalInfileWithoutInputStream() throws SQLException { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 3)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); + try (Connection connection = setConnection("&allowLocalInfile=true")) { try { PreparedStatement st = connection @@ -285,20 +296,29 @@ private void checkBigLocalInfile(long fileSize) throws Exception { */ @Test public void testSmallBigLocalInfileInputStream() throws Exception { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 3)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); + checkBigLocalInfile(256); } @Test public void test2xBigLocalInfileInputStream() throws Exception { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 3)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); + Assume.assumeTrue(checkMaxAllowedPacketMore40m("test2xBigLocalInfileInputStream")); checkBigLocalInfile(16777216 * 2); } @Test public void testMoreThanMaxAllowedPacketLocalInfileInputStream() throws Exception { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 3)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); + Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null); Assume.assumeFalse(sharedIsAurora()); Statement stmt = sharedConnection.createStatement(); diff --git a/src/test/java/org/mariadb/jdbc/PasswordEncodingTest.java b/src/test/java/org/mariadb/jdbc/PasswordEncodingTest.java index b9ec3c0bb..c1ae996f5 100644 --- a/src/test/java/org/mariadb/jdbc/PasswordEncodingTest.java +++ b/src/test/java/org/mariadb/jdbc/PasswordEncodingTest.java @@ -65,7 +65,7 @@ public class PasswordEncodingTest extends BaseTest { - private static final String exoticPwd = "abéï你好"; + private static final String exoticPwd = "Passw0rdabéï你好"; @Test public void testPwdCharset() throws Exception { diff --git a/src/test/java/org/mariadb/jdbc/StatementTest.java b/src/test/java/org/mariadb/jdbc/StatementTest.java index 5be2699e9..4419dba0b 100644 --- a/src/test/java/org/mariadb/jdbc/StatementTest.java +++ b/src/test/java/org/mariadb/jdbc/StatementTest.java @@ -276,7 +276,9 @@ public void testNoPartitionForGivenValue() throws SQLException { @Test public void testLoadDataInvalidColumn() throws SQLException { - Assume.assumeFalse(!isMariadbServer() && minVersion(8, 0, 0)); + Assume.assumeFalse( + (isMariadbServer() && minVersion(10, 4, 0) ) + || (!isMariadbServer() && minVersion(8, 0, 3))); try (Connection connection = setConnection("&allowLocalInfile=true")) { Statement statement = connection.createStatement(); try { @@ -310,6 +312,8 @@ public void testLoadDataInvalidColumn() throws SQLException { fail(); } assertEquals(ER_LOAD_DATA_INVALID_COLUMN_STATE, sqlException.getSQLState()); + //otherwise, localInfileInputStream will not be null, which cause false logic in readLocalInfilePacket and test like LocalInfileInputStreamTest#testLocalInfileUnValidInterceptor will fail if run after it + mysqlStatement.setLocalInfileInputStream(null); } } finally { try { diff --git a/src/test/java/org/mariadb/jdbc/TimeoutTest.java b/src/test/java/org/mariadb/jdbc/TimeoutTest.java index 9b59a318c..03aa66311 100644 --- a/src/test/java/org/mariadb/jdbc/TimeoutTest.java +++ b/src/test/java/org/mariadb/jdbc/TimeoutTest.java @@ -86,7 +86,7 @@ private static int selectValue(Connection conn, int value) @Test public void resultSetAfterSocketTimeoutTest() { //appveyor vm are very slow, cannot compare time - Assume.assumeTrue(System.getenv("APPVEYOR") == null); + Assume.assumeTrue(System.getenv("APPVEYOR") == null && System.getenv("DOCKER_SOCKET") == null); Assume.assumeFalse(sharedIsAurora()); int went = 0; From d0e04ebda724244c59d3dc18b65b2dcc2c3debfd Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 7 Jun 2019 12:32:40 +0200 Subject: [PATCH 02/19] [CONJ-710] Throw complete stackTrace when having an exception on XA Commands --- src/main/java/org/mariadb/jdbc/MariaXaResource.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/MariaXaResource.java b/src/main/java/org/mariadb/jdbc/MariaXaResource.java index 3a77d0b51..0ed4a3bfe 100644 --- a/src/main/java/org/mariadb/jdbc/MariaXaResource.java +++ b/src/main/java/org/mariadb/jdbc/MariaXaResource.java @@ -116,11 +116,14 @@ private XAException mapXaException(SQLException sqle) { xaErrorCode = 0; break; } + XAException xaException; if (xaErrorCode != 0) { - return new XAException(xaErrorCode); + xaException = new XAException(xaErrorCode); } else { - return new XAException(sqle.getMessage()); + xaException = new XAException(sqle.getMessage()); } + xaException.initCause(sqle); + return xaException; } /** From bb3bddcb9b92582b654aa5771135946645fac5ec Mon Sep 17 00:00:00 2001 From: rusher Date: Mon, 24 Jun 2019 15:11:50 +0200 Subject: [PATCH 03/19] [MENT-28] adding pipeline build testing id --- azure-pipelines.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 91c046ab9..590a35ff3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -46,12 +46,13 @@ jobs: displayName: 'Download server artifact files' inputs: buildType: 'specific' - project: 'test mariadb ent' - pipeline: 'rusher.MariaDBEnterprise' + project: '6d15af64-176c-496d-b583-fd2ae21d4df4' + pipeline: 'mariadb-corporation.MariaDBEnterprise' artifactName: Windows + buildId: 373 #buildVersionToDownload: 'latest' - buildId: 73 buildVersionToDownload: 'specific' + definition: '3' downloadPath: $(System.DefaultWorkingDirectory) - script: | choco install jdk8 -ia "INSTALLDIR=""c:\java""" @@ -114,14 +115,14 @@ jobs: displayName: 'Download server artifact files' inputs: buildType: 'specific' - project: 'test mariadb ent' - pipeline: 'rusher.MariaDBEnterprise' + downloadPath: $(System.DefaultWorkingDirectory) + project: '6d15af64-176c-496d-b583-fd2ae21d4df4' + pipeline: 'mariadb-corporation.MariaDBEnterprise' artifactName: $(containerImage) #buildVersionToDownload: 'latest' - buildId: 47 + definition: '3' buildVersionToDownload: 'specific' - downloadPath: $(System.DefaultWorkingDirectory) - + buildId: 373 - script: | sudo apt-get install -y software-properties-common wget wget -qO- 'https://github.com/tianon/pgp-happy-eyeballs/raw/master/hack-my-builds.sh' | bash From 0c29431fce9c4bcf2dfffb9cc3ca5c5ba8a20768 Mon Sep 17 00:00:00 2001 From: rusher Date: Mon, 24 Jun 2019 15:27:22 +0200 Subject: [PATCH 04/19] [MENT-28] using galera build from pipeline --- azure-pipelines.yml | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 590a35ff3..7b0dba9a4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -43,17 +43,18 @@ jobs: targetPath: $(System.DefaultWorkingDirectory) - task: DownloadPipelineArtifact@1 - displayName: 'Download server artifact files' + displayName: 'Download 10.4 enterprise server artifact files' inputs: buildType: 'specific' project: '6d15af64-176c-496d-b583-fd2ae21d4df4' pipeline: 'mariadb-corporation.MariaDBEnterprise' + branchName: 'refs/heads/10.4-enterprise' artifactName: Windows - buildId: 373 - #buildVersionToDownload: 'latest' - buildVersionToDownload: 'specific' definition: '3' downloadPath: $(System.DefaultWorkingDirectory) + #buildVersionToDownload: 'latest' + buildVersionToDownload: 'specific' + buildId: 373 - script: | choco install jdk8 -ia "INSTALLDIR=""c:\java""" type C:\ProgramData\chocolatey\logs\chocolatey.log @@ -112,33 +113,32 @@ jobs: displayName: Set up sudo - task: DownloadPipelineArtifact@1 - displayName: 'Download server artifact files' + displayName: 'Download 10.4 enterprise server artifact files' inputs: buildType: 'specific' downloadPath: $(System.DefaultWorkingDirectory) project: '6d15af64-176c-496d-b583-fd2ae21d4df4' pipeline: 'mariadb-corporation.MariaDBEnterprise' artifactName: $(containerImage) + branchName: 'refs/heads/10.4-enterprise' #buildVersionToDownload: 'latest' definition: '3' buildVersionToDownload: 'specific' buildId: 373 - - script: | - sudo apt-get install -y software-properties-common wget - wget -qO- 'https://github.com/tianon/pgp-happy-eyeballs/raw/master/hack-my-builds.sh' | bash - sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db - sudo apt-key adv --recv-keys --keyserver ha.pool.sks-keyservers.net F1656F24C74CD1D8 - displayName: 'Add galera signature keys' - - - script: | - sudo bash -c "echo 'deb http://yum.mariadb.org/galera/repo/deb xenial main' > /etc/apt/sources.list.d/galera-test-repo.list" - condition: eq(variables['containerImage'], 'ubuntu-1604') - displayName: 'Add xenial galera repo' - - script: | - sudo bash -c "echo 'deb http://yum.mariadb.org/galera/repo/deb bionic main' > /etc/apt/sources.list.d/galera-test-repo.list" - condition: eq(variables['containerImage'], 'ubuntu-1804') - displayName: 'Add bionic galera repo' + - task: DownloadPipelineArtifact@1 + displayName: 'Download galera server artifact files' + inputs: + buildType: 'specific' + downloadPath: $(System.DefaultWorkingDirectory) + project: '6d15af64-176c-496d-b583-fd2ae21d4df4' + pipeline: 'mariadb-corporation.es-galera' + artifactName: $(containerImage) + branchName: 'refs/heads/es-mariadb-4.x' + #buildVersionToDownload: 'latest' + definition: '2' + buildVersionToDownload: 'specific' + buildId: 337 - script: | ls -lrt . @@ -155,7 +155,7 @@ jobs: sudo debconf-set-selections <<< "mariadb-server-10.4 mysql-server/root_password_again password !Passw0rd" sudo apt-get update -y - sudo apt-get install --allow-unauthenticated -y curl libdbi-perl rsync socat libnuma1 libaio1 zlib1g-dev libreadline5 libjemalloc1 libsnappy1v5 libcrack2 galera-4 gawk lsof psmisc libaio1 perl libreadline5 + sudo apt-get install --allow-unauthenticated -y curl libdbi-perl rsync socat libnuma1 libaio1 zlib1g-dev libreadline5 libjemalloc1 libsnappy1v5 libcrack2 gawk lsof psmisc libaio1 perl libreadline5 echo 'Installing deb files' sudo apt install -f -y ./*.deb From 612c2fe9c3f252deb5322c6b168f72c95f27e3aa Mon Sep 17 00:00:00 2001 From: rusher Date: Tue, 9 Jul 2019 15:08:07 +0200 Subject: [PATCH 05/19] [CONJ-716] correcting possible NPE when logging information --- .../mariadb/jdbc/internal/logging/ProtocolLoggingProxy.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/internal/logging/ProtocolLoggingProxy.java b/src/main/java/org/mariadb/jdbc/internal/logging/ProtocolLoggingProxy.java index 03bd93e82..fbf709053 100644 --- a/src/main/java/org/mariadb/jdbc/internal/logging/ProtocolLoggingProxy.java +++ b/src/main/java/org/mariadb/jdbc/internal/logging/ProtocolLoggingProxy.java @@ -69,8 +69,8 @@ public class ProtocolLoggingProxy implements InvocationHandler { - private static final NumberFormat numberFormat = DecimalFormat.getInstance(); private static final Logger logger = LoggerFactory.getLogger(ProtocolLoggingProxy.class); + private final NumberFormat numberFormat; private final boolean profileSql; private final Long slowQueryThresholdNanos; private final int maxQuerySizeToLog; @@ -89,11 +89,11 @@ public ProtocolLoggingProxy(Protocol protocol, Options options) { this.slowQueryThresholdNanos = options.slowQueryThresholdNanos; this.maxQuerySizeToLog = options.maxQuerySizeToLog; this.logQuery = new LogQueryTool(options); + this.numberFormat = DecimalFormat.getInstance(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - long startTime = System.nanoTime(); try { switch (method.getName()) { @@ -104,6 +104,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl case "executeBatchClient": case "executeBatchServer": + final long startTime = System.nanoTime(); Object returnObj = method.invoke(protocol, args); if (logger.isInfoEnabled() && (profileSql || (slowQueryThresholdNanos != null From 663f828401c47366a3044214a79ce1f4f2be1322 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 19 Jul 2019 10:42:36 +0200 Subject: [PATCH 06/19] [MENT-28] azure testing on ubuntu using tar server artifact --- azure-pipelines.yml | 206 ++++++++++-------- .../java/org/mariadb/jdbc/ConnectionTest.java | 15 +- .../java/org/mariadb/jdbc/DriverTest.java | 13 +- src/test/java/org/mariadb/jdbc/SslTest.java | 5 +- .../org/mariadb/jdbc/StoredProcedureTest.java | 6 +- 5 files changed, 141 insertions(+), 104 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7b0dba9a4..673353661 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,10 +1,6 @@ resources: containers: - - container: ubuntu-1604 - image: ubuntu:16.04 - options: "--name ubuntu-1604 --add-host=mariadb.example.com:127.0.0.1 -v /usr/bin/docker:/tmp/docker:ro" - - container: ubuntu-1804 image: ubuntu:18.04 options: "--name ubuntu-1804 --add-host=mariadb.example.com:127.0.0.1 -v /usr/bin/docker:/tmp/docker:ro" @@ -20,8 +16,8 @@ jobs: - script: | java --version mkdir tmp + chmod 777 .travis/gen-ssl.sh .travis/gen-ssl.sh mariadb.example.com tmp - ls -lrt tmp cp -R tmp $BUILD_ARTIFACTSTAGINGDIRECTORY displayName: 'create SSL certificates' @@ -33,69 +29,75 @@ jobs: - job: windowsTest displayName: 'test windows' pool: - vmImage: 'win1803' + vmImage: 'windows-2019' dependsOn: - SSLFiles steps: - - task: DownloadPipelineArtifact@0 + - task: DownloadPipelineArtifact@2 + displayName: 'Download SSL files' inputs: artifactName: ssl_certs targetPath: $(System.DefaultWorkingDirectory) - - task: DownloadPipelineArtifact@1 - displayName: 'Download 10.4 enterprise server artifact files' + - task: DownloadPipelineArtifact@2 + displayName: 'Download 10.4 server' inputs: - buildType: 'specific' - project: '6d15af64-176c-496d-b583-fd2ae21d4df4' - pipeline: 'mariadb-corporation.MariaDBEnterprise' - branchName: 'refs/heads/10.4-enterprise' - artifactName: Windows - definition: '3' + source: 'specific' + project: '550599d3-6165-4abd-8c86-e3f7e53a1847' + artifact: 'Windows' + pipeline: 3 + runVersion: 'latestFromBranch' + runBranch: 'refs/heads/10.4-enterprise' downloadPath: $(System.DefaultWorkingDirectory) - #buildVersionToDownload: 'latest' - buildVersionToDownload: 'specific' - buildId: 373 + - script: | choco install jdk8 -ia "INSTALLDIR=""c:\java""" - type C:\ProgramData\chocolatey\logs\chocolatey.log Get-EnvironmentVariable -Name 'JAVA_HOME' -Scope 'Machine' choco install maven - echo %PATH% - echo %JAVA_HOME% - refreshenv - echo %PATH% - echo %JAVA_HOME% + rem type C:\ProgramData\chocolatey\logs\chocolatey.log displayName: 'install java + maven' - script: | - msiexec /i $(System.DefaultWorkingDirectory)\win_build\win\packaging\mariadb-10.4.5-winx64.msi INSTALLDIR=c:\projects\server SERVICENAME=mariadb ALLOWREMOTEROOTACCESS=true /qn + dir $(System.DefaultWorkingDirectory)\win_build\ + for /f %%a in ('dir /B $(System.DefaultWorkingDirectory)\win_build\mariadb-enterprise-10.*-winx64.msi') do set servername=$(System.DefaultWorkingDirectory)\win_build\%%a + echo %servername% + msiexec /i %servername% INSTALLDIR=c:\projects\server SERVICENAME=mariadb ALLOWREMOTEROOTACCESS=true /qn c:\projects\server\bin\mysql.exe -e "create database testj" --user=root + c:\projects\server\bin\mysql.exe -e "GRANT ALL on *.* to 'someUser'@'%' identified by 'Passw@rd2' with grant option;" --user=root displayName: 'install server' - script: | echo 127.0.0.1 mariadb.example.com >> %WINDIR%\System32\Drivers\Etc\Hosts - dir displayName: 'set hostname' - script: | set JAVA_HOME=C:\java\ set PATH=%PATH%;%JAVA_HOME%\bin java -version - C:\ProgramData\chocolatey\bin\mvn -version - C:\ProgramData\chocolatey\bin\mvn clean test -DdbUrl="jdbc:mariadb://mariadb.example.com:3306/testj?user=root" -DkeystorePath="$(System.DefaultWorkingDirectory)/tmp/client-keystore.jks" -DkeystorePassword="kspass" -DserverCertificatePath="$(System.DefaultWorkingDirectory)/tmp/server.crt" -Dkeystore2Path="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.jks" -Dkeystore2Password="kspass" -DkeyPassword="kspasskey" -Dkeystore2PathP12="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.p12" -DrunLongTest=false - displayName: 'run tests' + rem search maven version + + dir /B C:\ProgramData\chocolatey\lib\maven\apache-maven-*.*.* | findstr /x apache-maven-[0-9]\.[0-9]\.[0-9] > mavenversion.txt + set /p mavenversion= < mavenversion.txt + echo %mavenversion% + + C:\ProgramData\chocolatey\lib\maven\%mavenversion%\bin\mvn clean test -DdbUrl="jdbc:mariadb://mariadb.example.com:3306/testj?user=someUser&password=Passw@rd2" -DkeystorePath="$(System.DefaultWorkingDirectory)/tmp/client-keystore.jks" -DkeystorePassword="kspass" -DserverCertificatePath="$(System.DefaultWorkingDirectory)/tmp/server.crt" -Dkeystore2Path="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.jks" -Dkeystore2Password="kspass" -DkeyPassword="kspasskey" -Dkeystore2PathP12="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.p12" -DrunLongTest=false + if %ERRORLEVEL% EQU 0 ( + echo Success + ) else ( + echo exit code is %errorlevel% + exit /b %errorlevel% + ) + displayName: 'run tests' - job: RunInContainer pool: vmImage: 'ubuntu-16.04' + displayName: 'test ubuntu bionic' dependsOn: - SSLFiles strategy: matrix: - ubuntu-1604: - containerImage: ubuntu-1604 - containerName: xenial ubuntu-1804: containerImage: ubuntu-1804 containerName: bionic @@ -104,88 +106,120 @@ jobs: steps: - - task: DownloadPipelineArtifact@0 + - task: DownloadPipelineArtifact@2 inputs: artifactName: ssl_certs targetPath: $(System.DefaultWorkingDirectory) - script: /tmp/docker exec -t -u 0 $(containerImage) sh -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" -y install sudo" - displayName: Set up sudo + displayName: 'Set up sudo' - - task: DownloadPipelineArtifact@1 + - task: DownloadPipelineArtifact@2 displayName: 'Download 10.4 enterprise server artifact files' inputs: - buildType: 'specific' + source: 'specific' + project: '550599d3-6165-4abd-8c86-e3f7e53a1847' + artifact: '$(containerImage)' + pipeline: 3 + runVersion: 'latestFromBranch' + runBranch: 'refs/heads/10.4-enterprise' downloadPath: $(System.DefaultWorkingDirectory) - project: '6d15af64-176c-496d-b583-fd2ae21d4df4' - pipeline: 'mariadb-corporation.MariaDBEnterprise' - artifactName: $(containerImage) - branchName: 'refs/heads/10.4-enterprise' - #buildVersionToDownload: 'latest' - definition: '3' - buildVersionToDownload: 'specific' - buildId: 373 - - - task: DownloadPipelineArtifact@1 + + - task: DownloadPipelineArtifact@2 displayName: 'Download galera server artifact files' inputs: - buildType: 'specific' + source: 'specific' + project: '550599d3-6165-4abd-8c86-e3f7e53a1847' + artifact: $(containerImage) + runVersion: 'latestFromBranch' + pipeline: 2 + runBranch: 'refs/heads/es-mariadb-4.x' downloadPath: $(System.DefaultWorkingDirectory) - project: '6d15af64-176c-496d-b583-fd2ae21d4df4' - pipeline: 'mariadb-corporation.es-galera' - artifactName: $(containerImage) - branchName: 'refs/heads/es-mariadb-4.x' - #buildVersionToDownload: 'latest' - definition: '2' - buildVersionToDownload: 'specific' - buildId: 337 - script: | - ls -lrt . - echo "Installing server from deb" + sudo apt install -y default-jdk + sudo apt install -y maven + mvn -version + java -version + displayName: 'Install java + maven' + + - script: | + tar xf mariadb-enterprise* + sudo ln -fs /usr/share/zoneinfo/UTC /etc/localtime - rm -R mariadb-plugin* - rm -R *-dev.deb - rm -R *-test.deb - chmod 777 . sudo apt-get update && sudo apt-get install -y --no-install-recommends apt-transport-https ca-certificates tzdata pwgen export DEBIAN_FRONTEND="noninteractive" - sudo debconf-set-selections <<< "mariadb-server-10.4 mysql-server/root_password password !Passw0rd" - sudo debconf-set-selections <<< "mariadb-server-10.4 mysql-server/root_password_again password !Passw0rd" + sudo debconf-set-selections <<< "mariadb-server-10.4 mysql-server/root_password password P4ssw@rd" + sudo debconf-set-selections <<< "mariadb-server-10.4 mysql-server/root_password_again password P4ssw@rd" sudo apt-get update -y + sudo apt-get install --allow-unauthenticated -f -y libaio1 libaio-dev libxml2 libcurl4 curl libc-dev linux-libc-dev libc-dev-bin libdbi-perl rsync socat libnuma1 zlib1g-dev libreadline5 libjemalloc1 libsnappy1v5 libcrack2 gawk lsof psmisc perl libreadline5 - sudo apt-get install --allow-unauthenticated -y curl libdbi-perl rsync socat libnuma1 libaio1 zlib1g-dev libreadline5 libjemalloc1 libsnappy1v5 libcrack2 gawk lsof psmisc libaio1 perl libreadline5 + cd mariadb-enterprise*/ + sudo groupadd mysql + sudo useradd -g mysql mysql - echo 'Installing deb files' - sudo apt install -f -y ./*.deb + export PROJ_PATH=`pwd` + echo $PROJ_PATH - sudo ls -lrt /etc/mysql/ - sudo bash -c 'echo "ssl-ca=$(System.DefaultWorkingDirectory)/tmp/ca.crt" >> /etc/mysql/mariadb-enterprise.cnf' - sudo bash -c 'echo "ssl-cert=$(System.DefaultWorkingDirectory)/tmp/server.crt" >> /etc/mysql/mariadb-enterprise.cnf' - sudo bash -c 'echo "ssl-key=$(System.DefaultWorkingDirectory)/tmp/server.key" >> /etc/mysql/mariadb-enterprise.cnf' - sudo tail -n 500 /etc/mysql/mariadb-enterprise.cnf + cat <> my.cnf + [mysqld] + port=3306 + max_allowed_packet=16M + datadir=$PROJ_PATH/data + socket=/tmp/mysql.sock + user=mysql + ssl-ca=$(System.DefaultWorkingDirectory)/tmp/ca.crt + ssl-cert=$(System.DefaultWorkingDirectory)/tmp/server.crt + ssl-key=$(System.DefaultWorkingDirectory)/tmp/server.key + EOT - sudo service mysql restart + sudo chown mysql $PROJ_PATH/my.cnf + sudo tail -n 5000 $PROJ_PATH/my.cnf - displayName: 'install server' + sudo chmod 777 $PROJ_PATH + sudo ln -s $PROJ_PATH /usr/local/mysql - - script: | - sudo mysql -e "CREATE USER 'root'@'%' identified by 'Passw@rd2';" - sudo mysql -e "GRANT ALL on *.* to 'root'@'%' identified by 'Passw@rd2' with grant option;" - sudo mysql -e "CREATE DATABASE testj;" - displayName: 'Add non socket user' + sudo ./scripts/mysql_install_db --defaults-file=$PROJ_PATH/my.cnf --user=mysql + sudo chown -R root . + sudo chown -R mysql data - - script: | - sudo apt install -y default-jdk - sudo apt install -y maven - mvn -version - java -version - displayName: 'Install java + maven' + export PATH=$PATH:$PROJ_PATH/bin/ + + env: + WORKING_DIR: $(System.DefaultWorkingDirectory) + displayName: 'install server' - script: | - ls -lrt /usr/share/maven/bin/ - /usr/share/maven/bin/mvn clean test -DdbUrl="jdbc:mariadb://mariadb.example.com:3306/testj?user=root&password=Passw@rd2" -DkeystorePath="$(System.DefaultWorkingDirectory)/tmp/client-keystore.jks" -DkeystorePassword="kspass" -DserverCertificatePath="$(System.DefaultWorkingDirectory)/tmp/server.crt" -Dkeystore2Path="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.jks" -Dkeystore2Password="kspass" -DkeyPassword="kspasskey" -Dkeystore2PathP12="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.p12" -DrunLongTest=false + cd mariadb-enterprise*/ + sudo ./bin/mysqld --defaults-file=./my.cnf & + + for i in {30..0}; do + if sudo ./bin/mysql -e "SELECT 1" &> /dev/null; then + echo 'MySQL connected...' + break + fi + echo 'MySQL init process in progress...' + sleep 1 + done + if [ "$i" = 0 ]; then + echo >&2 'MySQL init process failed.' + sudo ./bin/mysql -e "SELECT 1" + exit 1 + fi + + sudo ./bin/mysql -e "CREATE USER 'someUser'@'%' identified by 'Passw@rd2';" + sudo ./bin/mysql -e "GRANT ALL on *.* to 'someUser'@'%' identified by 'Passw@rd2' with grant option;" + sudo ./bin/mysql -e "CREATE DATABASE testj;" + + cd .. + + /usr/share/maven/bin/mvn clean test -DdbUrl="jdbc:mariadb://mariadb.example.com:3306/testj?user=someUser&password=Passw@rd2" -DkeystorePath="$(System.DefaultWorkingDirectory)/tmp/client-keystore.jks" -DkeystorePassword="kspass" -DserverCertificatePath="$(System.DefaultWorkingDirectory)/tmp/server.crt" -Dkeystore2Path="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.jks" -Dkeystore2Password="kspass" -DkeyPassword="kspasskey" -Dkeystore2PathP12="$(System.DefaultWorkingDirectory)/tmp/fullclient-keystore.p12" -DrunLongTest=false + if [ $? -ne 0 ]; then + exit 1 + fi + cd mariadb-enterprise*/ + sudo ./bin/mysqladmin shutdown env: JAVA_HOME: "/usr/lib/jvm/default-java" MAVEN_HOME: "/opt/maven" diff --git a/src/test/java/org/mariadb/jdbc/ConnectionTest.java b/src/test/java/org/mariadb/jdbc/ConnectionTest.java index 2f8779b23..9c0bc6df0 100644 --- a/src/test/java/org/mariadb/jdbc/ConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/ConnectionTest.java @@ -589,20 +589,25 @@ public void verificationEd25519AuthPlugin() throws Throwable { throw new AssumptionViolatedException("server doesn't have ed25519 plugin, cancelling test"); } try { - stmt.execute("CREATE USER verificationEd25519AuthPlugin@'%' IDENTIFIED " - + "VIA ed25519 USING 'Dl7wP5om2lNrAfxWw3ooyZKDAoBztFNuhtVFdIrWfi0'"); + if (minVersion(10, 4)) { + stmt.execute("CREATE USER verificationEd25519AuthPlugin IDENTIFIED " + + "VIA ed25519 USING PASSWORD('MySup8%rPassw@ord')"); + } else { + stmt.execute("CREATE USER verificationEd25519AuthPlugin IDENTIFIED " + + "VIA ed25519 USING '6aW9C7ENlasUfymtfMvMZZtnkCVlcb1ssxOLJ0kj/AA'"); + } } catch (SQLException sqle) { //already existing } - stmt.execute("GRANT ALL on " + database + ".* to verificationEd25519AuthPlugin@'%'"); + stmt.execute("GRANT ALL on " + database + ".* to verificationEd25519AuthPlugin"); String url = "jdbc:mariadb://" + hostname + ((port == 0) ? "" : ":" + port) + "/" + database - + "?user=verificationEd25519AuthPlugin&password=!Passw0rd3&debug=true"; + + "?user=verificationEd25519AuthPlugin&password=MySup8%rPassw@ord"; try (Connection connection = openNewConnection(url)) { //must have succeed } - stmt.execute("drop user verificationEd25519AuthPlugin@'%'"); + stmt.execute("drop user verificationEd25519AuthPlugin"); } diff --git a/src/test/java/org/mariadb/jdbc/DriverTest.java b/src/test/java/org/mariadb/jdbc/DriverTest.java index d7df4f720..dc44f5562 100644 --- a/src/test/java/org/mariadb/jdbc/DriverTest.java +++ b/src/test/java/org/mariadb/jdbc/DriverTest.java @@ -1435,19 +1435,16 @@ public void localSocket() throws Exception { } String path = rs.getString(2); - st.execute("CREATE USER testSocket@'" + ((hostname == null) ? "localhost" : hostname) + "' IDENTIFIED VIA unix_socket"); - try { - st.execute("INSTALL SONAME 'auth_socket'"); - } catch (SQLException e) { - //dismiss, can already be installed - } - String connString = connU + "?user=testSocket&localSocket=" + path + "&profileSql=true"; + st.execute("CREATE USER testSocket@'localhost' IDENTIFIED BY 'MySup5%rPassw@ord'"); + st.execute("GRANT ALL on *.* to testSocket@'localhost' IDENTIFIED BY 'MySup5%rPassw@ord'"); + st.execute("FLUSH PRIVILEGES"); + String connString = connU + "?user=testSocket&password=MySup5%rPassw@ord&localSocket=" + path; System.out.println(connString); try (Connection connection = openConnection(connString, null)) { rs = connection.createStatement().executeQuery("select 1"); assertTrue(rs.next()); } - st.execute("DROP user testSocket@'" + ((hostname == null) ? "localhost" : hostname) + "'"); + st.execute("DROP user testSocket@'localhost'"); } @Test diff --git a/src/test/java/org/mariadb/jdbc/SslTest.java b/src/test/java/org/mariadb/jdbc/SslTest.java index ae96e307f..d1c6bc453 100644 --- a/src/test/java/org/mariadb/jdbc/SslTest.java +++ b/src/test/java/org/mariadb/jdbc/SslTest.java @@ -237,6 +237,7 @@ public void testServerRefuseProtocol() throws Exception { @Test public void useSslForceTlsV1() throws Exception { + Assume.assumeFalse(isMariadbServer() && minVersion(10, 4)); useSslForceTls("TLSv1"); } @@ -279,10 +280,10 @@ private List getSupportedProtocols() throws Exception { @Test public void useSslForceTlsV12AndCipher() throws Exception { - Assume.assumeFalse(Platform.isWindows()); + Assume.assumeFalse((Platform.isWindows() && !isMariadbServer()) || (isMariadbServer() && Platform.isWindows() && !minVersion(10, 4))); // Only test with MariaDB since MySQL community is compiled with yaSSL if (isMariadbServer()) { - useSslForceTls("TLSv1.2", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"); + useSslForceTls("TLSv1.2", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"); } } diff --git a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java index 8903b39de..f0096697d 100644 --- a/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java +++ b/src/test/java/org/mariadb/jdbc/StoredProcedureTest.java @@ -431,11 +431,11 @@ public void testMetaCatalogNoAccessToProcedureBodies() throws Exception { } catch (SQLException e) { //eat exception } - statement.execute("CREATE USER 'test_jdbc'@'%' IDENTIFIED BY 'test_jdbc'"); - statement.execute("GRANT ALL PRIVILEGES ON testj.* TO 'test_jdbc'@'%' WITH GRANT OPTION"); + statement.execute("CREATE USER 'test_jdbc'@'%' IDENTIFIED BY 'testJ@dc1'"); + statement.execute("GRANT ALL PRIVILEGES ON testj.* TO 'test_jdbc'@'%' IDENTIFIED BY 'testJ@dc1' WITH GRANT OPTION"); Properties properties = new Properties(); properties.put("user", "test_jdbc"); - properties.put("password", "test_jdbc"); + properties.put("password", "testJ@dc1"); createProcedure("testMetaCatalog", "(x int, out y int)\nBEGIN\nSET y = 2;\n end\n"); From ed04e0aa42bce4f1a61c3cb95555509cfda265ab Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 19 Jul 2019 12:20:09 +0200 Subject: [PATCH 07/19] [misc] test debugging output help --- src/test/java/org/mariadb/jdbc/BaseTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/org/mariadb/jdbc/BaseTest.java b/src/test/java/org/mariadb/jdbc/BaseTest.java index ca20585f7..a1466528f 100644 --- a/src/test/java/org/mariadb/jdbc/BaseTest.java +++ b/src/test/java/org/mariadb/jdbc/BaseTest.java @@ -321,6 +321,12 @@ public static void afterClassBaseTest() throws SQLException { while (it.hasNext()) { thread = it.next(); if (thread.getName().contains("MariaDb-bulk-")) { + if (thread.getState() != State.WAITING) { + //print stack trace to console. + for (StackTraceElement ste : thread.getStackTrace()) { + System.out.println(ste); + } + } assertEquals(State.WAITING, thread.getState()); } } From 384ea709d98b022d194399718646aaa0c44a3ec5 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 19 Jul 2019 18:06:51 +0200 Subject: [PATCH 08/19] [misc] test improvement for java 8 on windows --- src/test/java/org/mariadb/jdbc/BaseTest.java | 23 ++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/test/java/org/mariadb/jdbc/BaseTest.java b/src/test/java/org/mariadb/jdbc/BaseTest.java index a1466528f..a4a9ea903 100644 --- a/src/test/java/org/mariadb/jdbc/BaseTest.java +++ b/src/test/java/org/mariadb/jdbc/BaseTest.java @@ -315,19 +315,20 @@ public static void afterClassBaseTest() throws SQLException { e.printStackTrace(); } } - Iterator it = Thread.getAllStackTraces().keySet().iterator(); - Thread thread; - - while (it.hasNext()) { - thread = it.next(); - if (thread.getName().contains("MariaDb-bulk-")) { - if (thread.getState() != State.WAITING) { - //print stack trace to console. - for (StackTraceElement ste : thread.getStackTrace()) { - System.out.println(ste); + if (!Platform.isWindows()) { + Iterator it = Thread.getAllStackTraces().keySet().iterator(); + Thread thread; + while (it.hasNext()) { + thread = it.next(); + if (thread.getName().contains("MariaDb-bulk-")) { + if (thread.getState() != State.WAITING) { + //print stack trace to console. + for (StackTraceElement ste : thread.getStackTrace()) { + System.out.println(ste); + } } + assertEquals(State.WAITING, thread.getState()); } - assertEquals(State.WAITING, thread.getState()); } } } From ca1076c4146492a22d629dfa4967ff121209e0ed Mon Sep 17 00:00:00 2001 From: rusher Date: Wed, 24 Jul 2019 12:06:41 +0200 Subject: [PATCH 09/19] [CONJ-719] LocalTime fractional second implementation --- .../mariadb/jdbc/BasePrepareStatement.java | 5 +- .../send/parameters/LocalTimeParameter.java | 125 ++++++++++++ .../java/org/mariadb/jdbc/LocalTimeTest.java | 180 ++++++++++++++++++ 3 files changed, 308 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/mariadb/jdbc/internal/com/send/parameters/LocalTimeParameter.java create mode 100644 src/test/java/org/mariadb/jdbc/LocalTimeTest.java diff --git a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java index 3f5eb6417..bff535c54 100644 --- a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java +++ b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java @@ -84,6 +84,7 @@ import java.util.Calendar; import java.util.TimeZone; import org.mariadb.jdbc.internal.ColumnType; +import org.mariadb.jdbc.internal.com.send.parameters.LocalTimeParameter; import org.mariadb.jdbc.internal.com.send.parameters.BigDecimalParameter; import org.mariadb.jdbc.internal.com.send.parameters.ByteArrayParameter; import org.mariadb.jdbc.internal.com.send.parameters.ByteParameter; @@ -1052,7 +1053,7 @@ public void setObject(final int parameterIndex, final Object obj) throws SQLExce useFractionalSeconds, options)); } else if (obj instanceof LocalTime) { - setTime(parameterIndex, Time.valueOf((LocalTime) obj)); + setParameter(parameterIndex, new LocalTimeParameter((LocalTime) obj, useFractionalSeconds)); } else { //fallback to sending serialized object setParameter(parameterIndex, new SerializableParameter(obj, noBackslashEscapes)); @@ -1274,7 +1275,7 @@ private void setInternalObject(final int parameterIndex, final Object obj, useFractionalSeconds, options)); } else if (obj instanceof LocalTime) { - setTime(parameterIndex, Time.valueOf((LocalTime) obj)); + setParameter(parameterIndex, new LocalTimeParameter((LocalTime) obj, useFractionalSeconds)); } else { throw ExceptionMapper.getSqlException( "Could not set parameter in setObject, could not convert: " + obj.getClass() + " to " diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/LocalTimeParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/LocalTimeParameter.java new file mode 100644 index 000000000..9f901aa99 --- /dev/null +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/LocalTimeParameter.java @@ -0,0 +1,125 @@ +/* + * + * MariaDB Client for Java + * + * Copyright (c) 2012-2014 Monty Program Ab. + * Copyright (c) 2015-2018 MariaDB Ab. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this library; if not, write to Monty Program Ab info@montyprogram.com. + * + * + */ + + +package org.mariadb.jdbc.internal.com.send.parameters; + +import org.mariadb.jdbc.internal.ColumnType; +import org.mariadb.jdbc.internal.io.output.PacketOutputStream; + +import java.io.IOException; +import java.time.LocalTime; + +public class LocalTimeParameter implements Cloneable, ParameterHolder { + + private final LocalTime time; + private final boolean fractionalSeconds; + + /** + * Constructor. + * + * @param time time to write + * @param fractionalSeconds must fractional seconds be send. + */ + public LocalTimeParameter(LocalTime time, boolean fractionalSeconds) { + this.time = time; + this.fractionalSeconds = fractionalSeconds; + } + + /** + * Write Time parameter to outputStream. + * + * @param pos the stream to write to + */ + public void writeTo(final PacketOutputStream pos) throws IOException { + StringBuilder dateString = new StringBuilder(15); + dateString + .append(time.getHour() < 10 ? "0" : "") + .append(time.getHour()) + .append(time.getMinute() < 10 ? ":0" : ":") + .append(time.getMinute()) + .append(time.getSecond() < 10 ? ":0" : ":") + .append(time.getSecond()); + int microseconds = time.getNano() / 1000; + if (microseconds > 0 && fractionalSeconds) { + dateString.append("."); + if (microseconds % 1000 == 0) { + dateString.append(Integer.toString(microseconds / 1000 + 1000).substring(1)); + } else { + dateString.append(Integer.toString(microseconds + 1000000).substring(1)); + } + } + + pos.write(QUOTE); + pos.write(dateString.toString().getBytes()); + pos.write(QUOTE); + } + + public long getApproximateTextProtocolLength() { + return 15; + } + + /** + * Write data to socket in binary format. + * + * @param pos socket output stream + * @throws IOException if socket error occur + */ + + public void writeBinary(final PacketOutputStream pos) throws IOException { + int nano = time.getNano(); + if (fractionalSeconds && nano > 0) { + pos.write((byte) 12); + pos.write((byte) 0); + pos.writeInt(0); + pos.write((byte) time.getHour()); + pos.write((byte) time.getMinute()); + pos.write((byte) time.getSecond()); + pos.writeInt(nano / 1000); + } else { + pos.write((byte) 8);//length + pos.write((byte) 0); + pos.writeInt(0); + pos.write((byte) time.getHour()); + pos.write((byte) time.getMinute()); + pos.write((byte) time.getSecond()); + } + } + + public ColumnType getColumnType() { + return ColumnType.TIME; + } + + @Override + public String toString() { + return time.toString(); + } + + public boolean isNullData() { + return false; + } + + public boolean isLongData() { + return false; + } +} \ No newline at end of file diff --git a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java new file mode 100644 index 000000000..eeabbc5f1 --- /dev/null +++ b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java @@ -0,0 +1,180 @@ +package org.mariadb.jdbc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import java.sql.*; +import java.time.*; + +public class LocalTimeTest extends BaseTest { + + @Test + public void LocalTimeTest() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("CREATE TEMPORARY TABLE LocalTimeTest(val TIME(6), val2 TIME)"); + try (PreparedStatement prep = sharedConnection.prepareStatement("INSERT INTO LocalTimeTest value (?, ?)")) { + prep.setObject(1, LocalTime.of(1, 2, 3, 123456789)); + prep.setObject(2, LocalTime.of(2, 3, 4, 120000000)); + prep.execute(); + + prep.setObject(1, LocalTime.of(15, 14, 13, 12340000)); + prep.setObject(2, LocalTime.of(16, 15, 14, 12340000)); + prep.execute(); + + prep.setObject(1, LocalTime.of(5, 4, 3, 0)); + prep.setObject(2, LocalTime.of(6, 5, 4, 0)); + prep.execute(); + } + ResultSet rs = stmt.executeQuery("SELECT * FROM LocalTimeTest"); + assertTrue(rs.next()); + + assertEquals("01:02:03.123456", rs.getString(1)); + assertEquals(LocalTime.of(1, 2, 3, 123456000), rs.getObject(1, LocalTime.class)); + assertEquals("01:02:03", rs.getTime(1).toString()); + assertEquals(Time.valueOf("01:02:03").getTime() + 123 , rs.getTime(1).getTime()); + + assertEquals("02:03:04", rs.getString(2)); + assertEquals(LocalTime.of(2, 3, 4, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("02:03:04"), rs.getTime(2)); + assertEquals(Time.valueOf("02:03:04").getTime() , rs.getTime(2).getTime()); + + assertTrue(rs.next()); + + assertEquals("15:14:13.012340", rs.getString(1)); + assertEquals(LocalTime.of(15, 14, 13, 12340000), rs.getObject(1, LocalTime.class)); + assertEquals(Time.valueOf("15:14:13").toString(), rs.getTime(1).toString()); + assertEquals(Time.valueOf("15:14:13").getTime() + 12, rs.getTime(1).getTime()); + + assertEquals("16:15:14", rs.getString(2)); + assertEquals(LocalTime.of(16, 15, 14, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("16:15:14").toString(), rs.getTime(2).toString()); + assertEquals(Time.valueOf("16:15:14").getTime(), rs.getTime(2).getTime()); + + assertTrue(rs.next()); + + assertEquals("05:04:03.000000", rs.getString(1)); + assertEquals(LocalTime.of(5, 4, 3, 0), rs.getObject(1, LocalTime.class)); + assertEquals(Time.valueOf("05:04:03").toString(), rs.getTime(1).toString()); + assertEquals(Time.valueOf("05:04:03").getTime(), rs.getTime(1).getTime()); + + assertEquals("06:05:04", rs.getString(2)); + assertEquals(LocalTime.of(6, 5, 4, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("06:05:04").toString(), rs.getTime(2).toString()); + assertEquals(Time.valueOf("06:05:04").getTime(), rs.getTime(2).getTime()); + + assertFalse(rs.next()); + } + + + @Test + public void LocalDateTest() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("CREATE TEMPORARY TABLE LocalDateTest(val DATE)"); + try (PreparedStatement prep = sharedConnection.prepareStatement("INSERT INTO LocalDateTest value (?)")) { + prep.setObject(1, LocalDate.of(2000, 12, 31)); + prep.execute(); + prep.setObject(1, LocalDate.of(1000, 1, 1)); + prep.execute(); + prep.setObject(1, LocalDate.of(9999, 1, 31)); + prep.execute(); + } + ResultSet rs = stmt.executeQuery("SELECT * FROM LocalDateTest"); + assertTrue(rs.next()); + + assertEquals("2000-12-31", rs.getString(1)); + assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(1, LocalDate.class)); + + assertTrue(rs.next()); + assertEquals("1000-01-01", rs.getString(1)); + assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(1, LocalDate.class)); + + assertTrue(rs.next()); + assertEquals("9999-01-31", rs.getString(1)); + assertEquals(LocalDate.of(9999, 1, 31), rs.getObject(1, LocalDate.class)); + assertFalse(rs.next()); + } + + @Test + public void LocalDateTimeTest() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("CREATE TEMPORARY TABLE LocalDateTimeTest(val DATETIME(6), val2 DATETIME)"); + try (PreparedStatement prep = sharedConnection.prepareStatement("INSERT INTO LocalDateTimeTest value (?, ?)")) { + prep.setObject(1, LocalDateTime.of(2000, 12, 31,1, 2, 3, 123456789)); + prep.setObject(2, LocalDateTime.of(2000, 12, 31,2, 3, 4, 120000000)); + prep.execute(); + + prep.setObject(1, LocalDateTime.of(1000, 1, 1,15, 14, 13, 12340000)); + prep.setObject(2, LocalDateTime.of(1000, 1, 1,16, 15, 14, 12340000)); + prep.execute(); + + prep.setObject(1, LocalDateTime.of(9999, 12, 31,5, 4, 3, 0)); + prep.setObject(2, LocalDateTime.of(9999, 12, 31,6, 5, 4, 0)); + prep.execute(); + } + ResultSet rs = stmt.executeQuery("SELECT * FROM LocalDateTimeTest"); + assertTrue(rs.next()); + + assertEquals("2000-12-31 01:02:03.123456", rs.getString(1)); + assertEquals(LocalDateTime.of(2000, 12, 31,1, 2, 3, 123456000), rs.getObject(1, LocalDateTime.class)); + assertEquals("2000-12-31 01:02:03.123456", rs.getTimestamp(1).toString()); + assertEquals(Timestamp.valueOf("2000-12-31 01:02:03").getTime() + 123 , rs.getTimestamp(1).getTime()); + assertEquals(LocalTime.of(1, 2, 3, 123456000), rs.getObject(1, LocalTime.class)); + assertEquals("01:02:03", rs.getTime(1).toString()); + assertEquals(Timestamp.valueOf("2000-12-31 01:02:03").getTime() + 123 , rs.getTime(1).getTime()); + assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(1, LocalDate.class)); + + assertEquals("2000-12-31 02:03:04.0", rs.getString(2)); + assertEquals(LocalDateTime.of(2000, 12, 31,2, 3, 4, 0), rs.getObject(2, LocalDateTime.class)); + assertEquals(Timestamp.valueOf("2000-12-31 02:03:04"), rs.getTimestamp(2)); + assertEquals(Timestamp.valueOf("2000-12-31 02:03:04").getTime() , rs.getTimestamp(2).getTime()); + assertEquals(LocalTime.of(2, 3, 4, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("02:03:04").toString(), rs.getTime(2).toString()); + assertEquals(Timestamp.valueOf("2000-12-31 02:03:04").getTime() , rs.getTime(2).getTime()); + assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(2, LocalDate.class)); + + assertTrue(rs.next()); + + assertEquals("1000-01-01 15:14:13.01234", rs.getString(1)); + assertEquals(LocalDateTime.of(1000, 1, 1,15, 14, 13, 12340000), rs.getObject(1, LocalDateTime.class)); + assertEquals(Timestamp.valueOf("1000-01-01 15:14:13.01234").toString(), rs.getTimestamp(1).toString()); + assertEquals(Timestamp.valueOf("1000-01-01 15:14:13").getTime() + 12, rs.getTimestamp(1).getTime()); + assertEquals(LocalTime.of(15, 14, 13, 12340000), rs.getObject(1, LocalTime.class)); + assertEquals(Time.valueOf("15:14:13").toString(), rs.getTime(1).toString()); + assertEquals(Timestamp.valueOf("1000-01-01 15:14:13.01234").getTime(), rs.getTime(1).getTime()); + assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(1, LocalDate.class)); + + assertEquals("1000-01-01 16:15:14.0", rs.getString(2)); + assertEquals(LocalDateTime.of(1000, 1, 1,16, 15, 14, 0), rs.getObject(2, LocalDateTime.class)); + assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").toString(), rs.getTimestamp(2).toString()); + assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").getTime(), rs.getTimestamp(2).getTime()); + assertEquals(LocalTime.of(16, 15, 14, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("16:15:14").toString(), rs.getTime(2).toString()); + assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").getTime(), rs.getTime(2).getTime()); + assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(2, LocalDate.class)); + + assertTrue(rs.next()); + + assertEquals("9999-12-31 05:04:03.0", rs.getString(1)); + assertEquals(LocalDateTime.of(9999, 12, 31, 5, 4, 3, 0), rs.getObject(1, LocalDateTime.class)); + assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").toString(), rs.getTimestamp(1).toString()); + assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").getTime(), rs.getTimestamp(1).getTime()); + assertEquals(LocalTime.of(5, 4, 3, 0), rs.getObject(1, LocalTime.class)); + assertEquals(Time.valueOf("05:04:03").toString(), rs.getTime(1).toString()); + assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").getTime(), rs.getTime(1).getTime()); + assertEquals(LocalDate.of(9999, 12, 31), rs.getObject(1, LocalDate.class)); + + assertEquals("9999-12-31 06:05:04.0", rs.getString(2)); + assertEquals(LocalDateTime.of(9999, 12, 31, 6, 5, 4, 0), rs.getObject(2, LocalDateTime.class)); + assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").toString(), rs.getTimestamp(2).toString()); + assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").getTime(), rs.getTimestamp(2).getTime()); + assertEquals(LocalTime.of(6, 5, 4, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("06:05:04").toString(), rs.getTime(2).toString()); + assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").getTime(), rs.getTime(2).getTime()); + assertEquals(LocalDate.of(9999, 12, 31), rs.getObject(1, LocalDate.class)); + + assertFalse(rs.next()); + } +} From d8603ee42179ffcc6282e003d62ed86176e0856e Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 26 Jul 2019 14:21:56 +0200 Subject: [PATCH 10/19] [misc] prepare statement boolean / byte better logging when exception --- .../mariadb/jdbc/BasePrepareStatement.java | 3 +- .../com/send/parameters/BooleanParameter.java | 73 +++++++++++++++++++ .../com/send/parameters/ByteParameter.java | 13 ++-- src/test/java/org/mariadb/jdbc/BaseTest.java | 3 +- .../java/org/mariadb/jdbc/BooleanTest.java | 17 +++++ .../java/org/mariadb/jdbc/DriverTest.java | 5 +- 6 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/mariadb/jdbc/internal/com/send/parameters/BooleanParameter.java diff --git a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java index bff535c54..b168118a9 100644 --- a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java +++ b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java @@ -86,6 +86,7 @@ import org.mariadb.jdbc.internal.ColumnType; import org.mariadb.jdbc.internal.com.send.parameters.LocalTimeParameter; import org.mariadb.jdbc.internal.com.send.parameters.BigDecimalParameter; +import org.mariadb.jdbc.internal.com.send.parameters.BooleanParameter; import org.mariadb.jdbc.internal.com.send.parameters.ByteArrayParameter; import org.mariadb.jdbc.internal.com.send.parameters.ByteParameter; import org.mariadb.jdbc.internal.com.send.parameters.DateParameter; @@ -1478,7 +1479,7 @@ public void setBinaryStream(final int parameterIndex, final InputStream stream, * PreparedStatement */ public void setBoolean(final int parameterIndex, final boolean value) throws SQLException { - setParameter(parameterIndex, new ByteParameter(value ? (byte) 1 : (byte) 0)); + setParameter(parameterIndex, new BooleanParameter(value)); } /** diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/BooleanParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/BooleanParameter.java new file mode 100644 index 000000000..8aac9f390 --- /dev/null +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/BooleanParameter.java @@ -0,0 +1,73 @@ +/* + * + * MariaDB Client for Java + * + * Copyright (c) 2012-2014 Monty Program Ab. + * Copyright (c) 2015-2019 MariaDB Ab. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this library; if not, write to Monty Program Ab info@montyprogram.com. + * + */ + +package org.mariadb.jdbc.internal.com.send.parameters; + +import org.mariadb.jdbc.internal.ColumnType; +import org.mariadb.jdbc.internal.io.output.PacketOutputStream; + +import java.io.IOException; + +public class BooleanParameter implements Cloneable, ParameterHolder { + + private final boolean value; + + public BooleanParameter(boolean value) { + this.value = value; + } + + public void writeTo(final PacketOutputStream os) throws IOException { + os.write(value ? '1' : '0'); + } + + public long getApproximateTextProtocolLength() { + return 1; + } + + /** + * Write data to socket in binary format. + * + * @param pos socket output stream + * @throws IOException if socket error occur + */ + public void writeBinary(final PacketOutputStream pos) throws IOException { + pos.write(value ? 1 : 0); + } + + public ColumnType getColumnType() { + return ColumnType.TINYINT; + } + + @Override + public String toString() { + return Boolean.toString(value); + } + + public boolean isNullData() { + return false; + } + + public boolean isLongData() { + return false; + } + +} diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ByteParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ByteParameter.java index 48259fed0..0a8e0252f 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ByteParameter.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ByteParameter.java @@ -58,18 +58,21 @@ public class ByteParameter implements Cloneable, ParameterHolder { - private final byte value; + private final int value; + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); public ByteParameter(byte value) { - this.value = value; + this.value = value & 0xFF; } public void writeTo(final PacketOutputStream os) throws IOException { - os.write(String.valueOf(value).getBytes()); + os.write("0x"); + os.write(hexArray[value >>> 4]); + os.write(hexArray[value & 0x0F]); } public long getApproximateTextProtocolLength() { - return String.valueOf(value).getBytes().length * 2; + return 4; } /** @@ -88,7 +91,7 @@ public ColumnType getColumnType() { @Override public String toString() { - return Byte.toString(value); + return "0x" + hexArray[value >>> 4] + hexArray[value & 0x0F]; } public boolean isNullData() { diff --git a/src/test/java/org/mariadb/jdbc/BaseTest.java b/src/test/java/org/mariadb/jdbc/BaseTest.java index a4a9ea903..e1470e312 100644 --- a/src/test/java/org/mariadb/jdbc/BaseTest.java +++ b/src/test/java/org/mariadb/jdbc/BaseTest.java @@ -74,6 +74,7 @@ import java.text.NumberFormat; import java.util.HashSet; import java.util.Iterator; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Random; @@ -107,7 +108,7 @@ public class BaseTest { private static final Set tempViewList = new HashSet<>(); private static final Set tempProcedureList = new HashSet<>(); private static final Set tempFunctionList = new HashSet<>(); - private static final NumberFormat numberFormat = DecimalFormat.getInstance(); + private static final NumberFormat numberFormat = DecimalFormat.getInstance(Locale.ROOT); protected static String connU; protected static String connUri; protected static String connDnsUri; diff --git a/src/test/java/org/mariadb/jdbc/BooleanTest.java b/src/test/java/org/mariadb/jdbc/BooleanTest.java index 84a6d4239..3d302191a 100644 --- a/src/test/java/org/mariadb/jdbc/BooleanTest.java +++ b/src/test/java/org/mariadb/jdbc/BooleanTest.java @@ -99,6 +99,23 @@ public void testBoolean() throws SQLException { } } + @Test + public void testBooleanSet() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("CREATE TEMPORARY TABLE testBooleanSet (test BOOLEAN)"); + try (PreparedStatement prep = sharedConnection.prepareStatement("INSERT INTO testBooleanSet VALUE (?)")) { + prep.setBoolean(1, true); + prep.execute(); + prep.setBoolean(1, false); + prep.execute(); + } + ResultSet rs = stmt.executeQuery("select * from testBooleanSet"); + assertTrue(rs.next()); + assertTrue(rs.getBoolean(1)); + assertTrue(rs.next()); + assertFalse(rs.getBoolean(1)); + } + @Test public void testBooleanString() throws SQLException { Statement stmt = sharedConnection.createStatement(); diff --git a/src/test/java/org/mariadb/jdbc/DriverTest.java b/src/test/java/org/mariadb/jdbc/DriverTest.java index dc44f5562..73aad7148 100644 --- a/src/test/java/org/mariadb/jdbc/DriverTest.java +++ b/src/test/java/org/mariadb/jdbc/DriverTest.java @@ -1491,7 +1491,7 @@ public void sharedMemory() throws Exception { @Test public void preparedStatementToString() throws Exception { - try (PreparedStatement ps = sharedConnection.prepareStatement("SELECT ?,?,?,?,?,?")) { + try (PreparedStatement ps = sharedConnection.prepareStatement("SELECT ?,?,?,?,?,?,?")) { ps.setInt(1, 1); ps.setBigDecimal(2, new BigDecimal("1")); ps.setString(3, "one"); @@ -1499,7 +1499,8 @@ public void preparedStatementToString() throws Exception { Calendar calendar = new GregorianCalendar(1972, 3, 22); ps.setDate(5, new Date(calendar.getTime().getTime())); ps.setDouble(6, 1.5); - assertEquals("sql : 'SELECT ?,?,?,?,?,?', parameters : [1,1,'one',1,'1972-04-22',1.5]", + ps.setByte(7, (byte) 0xfe); + assertEquals("sql : 'SELECT ?,?,?,?,?,?,?', parameters : [1,1,'one',true,'1972-04-22',1.5,0xFE]", ps.toString()); } } From c7074aad69e129b97e0e23a7e1c7472df2a924ff Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 26 Jul 2019 15:33:10 +0200 Subject: [PATCH 11/19] [CONJ-717] conversion function support for other data type than default MariaDB conversion type. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MariaDB support datatype conversion for : BINARY CHAR DATE DATETIME DECIMAL[(M[,D])] DOUBLE FLOAT — From MariaDB 10.4.5 INTEGER TIME JDBC spec 4.2 support (C.5): CONVERT(value, SQLtype) value converted to SQLtype where SQLtype may be one of the following SQL types: SQL_BIGINT, SQL_BINARY, SQL_BIT, SQL_BLOB, SQL_BOOLEAN, SQL_CHAR, SQL_CLOB, SQL_DATE, SQL_DECIMAL, SQL_DATALINK, SQL_DOUBLE, SQL_FLOAT, SQL_INTEGER, SQL_LONGVARBINARY, SQL_LONGNVARCHAR, SQL_LONGVARCHAR, SQL_NCHAR, SQL_NCLOB, SQL_NUMERIC, SQL_NVARCHAR, SQL_REAL, SQL_ROWID, SQL_SQLXML, SQL_SMALLINT, SQL_TIME, SQL_TIMESTAMP, SQL_TINYINT, SQL_VARBINARY, or SQL_VARCHAR MariaDB server support automatic conversion, but datatype must correspond to expected type (i.e convert(2147483648, INTEGER ) Will result in a BIG_INT datatype). --- .../mariadb/jdbc/MariaDbDatabaseMetaData.java | 229 +++++++++++++++--- .../org/mariadb/jdbc/internal/util/Utils.java | 159 ++++++------ .../org/mariadb/jdbc/ScalarFunctionsTest.java | 136 +++++++++++ 3 files changed, 415 insertions(+), 109 deletions(-) create mode 100644 src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java index 1fb72e960..ad9024428 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java @@ -230,7 +230,7 @@ private static int getImportedKeyAction(String actionKey) { * @throws ParseException exception */ private static ResultSet getImportedKeys(String tableDef, String tableName, String catalog, - MariaDbConnection connection) throws ParseException { + MariaDbConnection connection) throws ParseException { String[] columnNames = { "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", @@ -628,7 +628,7 @@ private String mapTableTypes(String tableType) { * @see #getSearchStringEscape */ public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, - String[] types) + String[] types) throws SQLException { StringBuilder sql = @@ -737,7 +737,7 @@ public ResultSet getTables(String catalog, String schemaPattern, String tableNam * @see #getSearchStringEscape */ public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) + String columnNamePattern) throws SQLException { Options options = urlParser.getOptions(); String sql = "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, COLUMN_NAME," @@ -999,7 +999,7 @@ public ResultSet getImportedKeysUsingShowCreateTable(String catalog, String tabl * @throws SQLException if a database access error occurs */ public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, - final boolean nullable) + final boolean nullable) throws SQLException { if (table == null) { @@ -1083,7 +1083,7 @@ public boolean generatedKeyAlwaysReturned() { * @since 1.7 */ public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) throws SQLException { + String columnNamePattern) throws SQLException { return connection.createStatement().executeQuery( "SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM," + "' ' TABLE_NAME, ' ' COLUMN_NAME, 0 DATA_TYPE, 0 COLUMN_SIZE, 0 DECIMAL_DIGITS," @@ -1140,7 +1140,7 @@ public String getDatabaseProductName() throws SQLException { return "MySQL"; } if (connection.getProtocol().isServerMariaDb() - && connection.getProtocol().getServerVersion().toLowerCase(Locale.ROOT).contains("mariadb")) { + && connection.getProtocol().getServerVersion().toLowerCase(Locale.ROOT).contains("mariadb")) { return "MariaDB"; } return "MySQL"; @@ -1314,8 +1314,159 @@ public boolean supportsConvert() { return true; } + /** + * Retrieves whether this database supports the JDBC scalar function CONVERT for conversions between the JDBC types + * fromType and toType. The JDBC types are the generic SQL data types defined in java.sql.Types. + * + * @param fromType the type to convert from; one of the type codes from the class java.sql.Types + * @param toType the type to convert to; one of the type codes from the class java.sql.Types + * @return true if so; false otherwise + */ public boolean supportsConvert(int fromType, int toType) { - return false; + switch (fromType) { + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.REAL: + case Types.FLOAT: + case Types.DECIMAL: + case Types.NUMERIC: + case Types.DOUBLE: + case Types.BIT: + case Types.BOOLEAN: + switch (toType) { + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.REAL: + case Types.FLOAT: + case Types.DECIMAL: + case Types.NUMERIC: + case Types.DOUBLE: + case Types.BIT: + case Types.BOOLEAN: + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + return true; + default: + return false; + } + + case Types.BLOB: + switch (toType) { + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.REAL: + case Types.FLOAT: + case Types.DECIMAL: + case Types.NUMERIC: + case Types.DOUBLE: + case Types.BIT: + case Types.BOOLEAN: + return true; + default: + return false; + } + + case Types.CHAR: + case Types.CLOB: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + switch (toType) { + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.NUMERIC: + case Types.DECIMAL: + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + case Types.DATE: + case Types.TIME: + case Types.TIMESTAMP: + case Types.BLOB: + case Types.CLOB: + case Types.BOOLEAN: + case Types.NCHAR: + case Types.LONGNVARCHAR: + case Types.NCLOB: + return true; + default: + return false; + } + + case Types.DATE: + switch (toType) { + case Types.DATE: + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + return true; + + default: + return false; + } + + case Types.TIME: + switch (toType) { + case Types.TIME: + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + return true; + default: + return false; + } + + case Types.TIMESTAMP: + switch (toType) { + case Types.TIMESTAMP: + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + case Types.TIME: + case Types.DATE: + return true; + default: + return false; + } + default: + return false; + } } public boolean supportsTableCorrelationNames() { @@ -1331,7 +1482,7 @@ public boolean supportsExpressionsInOrderBy() { } public boolean supportsOrderByUnrelated() { - return false; + return true; } public boolean supportsGroupBy() { @@ -1384,16 +1535,16 @@ public boolean supportsANSI92EntryLevelSQL() { @Override public boolean supportsANSI92IntermediateSQL() { - return false; + return true; } @Override public boolean supportsANSI92FullSQL() { - return false; + return true; } public boolean supportsIntegrityEnhancementFacility() { - return false; + return true; } public boolean supportsOuterJoins() { @@ -1401,7 +1552,7 @@ public boolean supportsOuterJoins() { } public boolean supportsFullOuterJoins() { - return false; + return true; } public boolean supportsLimitedOuterJoins() { @@ -1806,8 +1957,8 @@ private boolean haveInformationSchemaParameters() { * @see #getSearchStringEscape */ public ResultSet getProcedureColumns(String catalog, String schemaPattern, - String procedureNamePattern, - String columnNamePattern) throws SQLException { + String procedureNamePattern, + String columnNamePattern) throws SQLException { String sql; if (haveInformationSchemaParameters()) { @@ -1972,14 +2123,14 @@ public ResultSet getProcedureColumns(String catalog, String schemaPattern, * @param columnNamePattern a parameter name pattern; must match the parameter or column name as * it is stored in the database * @return ResultSet - each row describes a user function parameter, column or - * return type + * return type * @throws SQLException if a database access error occurs * @see #getSearchStringEscape * @since 1.6 */ public ResultSet getFunctionColumns(String catalog, String schemaPattern, - String functionNamePattern, - String columnNamePattern) throws SQLException { + String functionNamePattern, + String columnNamePattern) throws SQLException { String sql; if (haveInformationSchemaParameters()) { @@ -2076,7 +2227,7 @@ public ResultSet getTableTypes() throws SQLException { * @see #getSearchStringEscape */ public ResultSet getColumnPrivileges(String catalog, String schema, String table, - String columnNamePattern) throws SQLException { + String columnNamePattern) throws SQLException { if (table == null) { throw new SQLException("'table' parameter must not be null"); @@ -2252,7 +2403,7 @@ public ResultSet getVersionColumns(String catalog, String schema, String table) * @see #getImportedKeys */ public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, - String foreignCatalog, String foreignSchema, String foreignTable) + String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { String sql = @@ -2535,7 +2686,7 @@ public ResultSet getTypeInfo() { * @throws SQLException if a database access error occurs */ public ResultSet getIndexInfo(String catalog, String schema, String table, - boolean unique, boolean approximate) throws SQLException { + boolean unique, boolean approximate) throws SQLException { String sql = "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, NON_UNIQUE, " @@ -2681,7 +2832,7 @@ public boolean supportsBatchUpdates() { */ @Override public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, - int[] types) + int[] types) throws SQLException { String sql = "SELECT ' ' TYPE_CAT, NULL TYPE_SCHEM, ' ' TYPE_NAME, ' ' CLASS_NAME, 0 DATA_TYPE, ' ' REMARKS, 0 BASE_TYPE" @@ -2738,7 +2889,7 @@ public boolean supportsGetGeneratedKeys() { * @param schemaPattern a schema name pattern; "" retrieves those without a schema * @param typeNamePattern a UDT name pattern; may be a fully-qualified name * @return a ResultSet object in which a row gives information about the designated - * UDT + * UDT * @throws SQLException if a database access error occurs * @see #getSearchStringEscape * @since 1.4 @@ -2857,7 +3008,7 @@ public ResultSet getSuperTables(String catalog, String schemaPattern, String tab * @since 1.4 */ public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, - String attributeNamePattern) throws SQLException { + String attributeNamePattern) throws SQLException { String sql = "SELECT ' ' TYPE_CAT, ' ' TYPE_SCHEM, ' ' TYPE_NAME, ' ' ATTR_NAME, 0 DATA_TYPE," @@ -2981,22 +3132,22 @@ public ResultSet getClientInfoProperties() { *

Each function description has the the following columns:

* *
    - *
  1. FUNCTION_CAT String {@code =>} function catalog (may be null)
  2. - *
  3. FUNCTION_SCHEM String {@code =>} function schema (may be null)
  4. - *
  5. FUNCTION_NAME String {@code =>} function name. This is the name used to invoke - * the function
  6. - *
  7. REMARKS String {@code =>} explanatory comment on the function
  8. - *
  9. FUNCTION_TYPE short {@code =>} kind of function: - *
      - *
    • functionResultUnknown - Cannot determine if a return value or table will be - * returned
    • - *
    • functionNoTable- Does not return a table
    • - *
    • functionReturnsTable - Returns a table
    • - *
    - *
  10. - *
  11. SPECIFIC_NAME String {@code =>} the name which uniquely identifies this function - * within its schema. This is a user specified, or DBMS generated, name that may be different - * then the FUNCTION_NAME for example with overload functions
  12. + *
  13. FUNCTION_CAT String {@code =>} function catalog (may be null)
  14. + *
  15. FUNCTION_SCHEM String {@code =>} function schema (may be null)
  16. + *
  17. FUNCTION_NAME String {@code =>} function name. This is the name used to invoke + * the function
  18. + *
  19. REMARKS String {@code =>} explanatory comment on the function
  20. + *
  21. FUNCTION_TYPE short {@code =>} kind of function: + *
      + *
    • functionResultUnknown - Cannot determine if a return value or table will be + * returned
    • + *
    • functionNoTable- Does not return a table
    • + *
    • functionReturnsTable - Returns a table
    • + *
    + *
  22. + *
  23. SPECIFIC_NAME String {@code =>} the name which uniquely identifies this function + * within its schema. This is a user specified, or DBMS generated, name that may be different + * then the FUNCTION_NAME for example with overload functions
  24. *
* *

A user may not have diff --git a/src/main/java/org/mariadb/jdbc/internal/util/Utils.java b/src/main/java/org/mariadb/jdbc/internal/util/Utils.java index d5a21e2d1..d5fa69809 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/Utils.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/Utils.java @@ -180,7 +180,7 @@ public static String escapeString(String value, boolean noBackslashEscapes) { * @throws UnsupportedEncodingException if passwordCharacterEncoding is not a valid charset name */ public static byte[] encryptPassword(final String password, final byte[] seed, - String passwordCharacterEncoding) + String passwordCharacterEncoding) throws NoSuchAlgorithmException, UnsupportedEncodingException { if (password == null || password.isEmpty()) { @@ -249,20 +249,21 @@ public static byte[] copyRange(byte[] orig, int from, int to) { } /** - * Helper function to replace function parameters in escaped string. 3 functions are handles : - - * CONVERT(value, type) , we replace SQL_XXX types with XXX, i.e SQL_INTEGER with INTEGER - - * TIMESTAMPDIFF(type, ...) or TIMESTAMPADD(type, ...) , we replace SQL_TSI_XXX in type with XXX, - * i.e SQL_TSI_HOUR with HOUR + * Helper function to replace function parameters in escaped string. + * 3 functions are handles : + *

    + *
  • CONVERT(value, type): replacing SQL_XXX types to convertible type, i.e SQL_BIGINT to INTEGER
  • + *
  • TIMESTAMPDIFF(type, ...): replacing type SQL_TSI_XXX in type with XXX, i.e SQL_TSI_HOUR with HOUR
  • + *
  • TIMESTAMPADD(type, ...): replacing type SQL_TSI_XXX in type with XXX, i.e SQL_TSI_HOUR with HOUR
  • + *
+ * caution: this use MariaDB server conversion: 'SELECT CONVERT('2147483648', INTEGER)' will return a BIGINT. + * MySQL will throw a syntax error. * * @param functionString - input string * @return unescaped string */ private static String replaceFunctionParameter(String functionString) { - if (!functionString.contains("SQL_")) { - return functionString; - } - char[] input = functionString.toCharArray(); StringBuilder sb = new StringBuilder(); int index; @@ -277,52 +278,91 @@ private static String replaceFunctionParameter(String functionString) { sb.append(input[index]); } String func = sb.toString().toLowerCase(Locale.ROOT); + switch (func) { + case "convert": + // Handle "convert(value, type)" case + // extract last parameter, after the last ',' + int lastCommaIndex = functionString.lastIndexOf(','); + + for (index = lastCommaIndex + 1; index < input.length; index++) { + if (!Character.isWhitespace(input[index])) { + break; + } + } + + int endParam = index + 1; + for (; endParam < input.length; endParam++) { + if ((input[endParam] < 'a' || input[endParam] > 'z') && (input[endParam] < 'A' || input[endParam] > 'Z') && input[endParam] != '_'){ + break; + } + } + String typeParam = new String(input, index, endParam - index).toUpperCase(Locale.ROOT); + if (typeParam.startsWith("SQL_")) typeParam = typeParam.substring(4); + + switch (typeParam) { + case "BIGINT": + case "BOOLEAN": + case "SMALLINT": + case "TINYINT": + case "BIT": + typeParam = "INTEGER"; + break; - if ("convert".equals(func) || "timestampdiff".equals(func) || "timestampadd".equals(func)) { - String paramPrefix; + case "BLOB": + case "VARBINARY": + case "LONGVARBINARY": + case "ROWID": + typeParam = "BINARY"; + break; + + case "NCHAR": + case "CLOB": + case "NCLOB": + case "DATALINK": + case "VARCHAR": + case "NVARCHAR": + case "LONGVARCHAR": + case "LONGNVARCHAR": + case "SQLXML": + case "LONGNCHAR": + typeParam = "CHAR"; + break; + + case "FLOAT": + typeParam = "DOUBLE"; + break; + + case "REAL": + case "NUMERIC": + typeParam = "DECIMAL"; + break; + + case "TIMESTAMP": + typeParam = "DATETIME"; + break; + } + return new String(input, 0, index) + typeParam + new String(input, endParam, input.length - endParam); - if ("timestampdiff".equals(func) || "timestampadd".equals(func)) { + case "timestampdiff": + case "timestampadd": // Skip to first parameter for (; index < input.length; index++) { if (!Character.isWhitespace(input[index]) && input[index] != '(') { break; } } - if (index == input.length) { - return new String(input); + if (index < input.length - 8) { + String paramPrefix = new String(input, index, 8); + if ("SQL_TSI_".equals(paramPrefix)) { + return new String(input, 0, index) + new String(input, index + 8,input.length - (index + 8)); + } } - if (index >= input.length - 8) { - return new String(input); - } - paramPrefix = new String(input, index, 8); - if ("SQL_TSI_".equals(paramPrefix)) { - return new String(input, 0, index) + new String(input, index + 8, - input.length - (index + 8)); - } - return new String(input); - } + default: + return functionString; + } - // Handle "convert(value, type)" case - // extract last parameter, after the last ',' - int lastCommaIndex = functionString.lastIndexOf(','); - for (index = lastCommaIndex + 1; index < input.length; index++) { - if (!Character.isWhitespace(input[index])) { - break; - } - } - if (index >= input.length - 4) { - return new String(input); - } - paramPrefix = new String(input, index, 4); - if ("SQL_".equals(paramPrefix)) { - return new String(input, 0, index) + new String(input, index + 4, - input.length - (index + 4)); - } - - } - return new String(input); } private static String resolveEscapes(String escaped, boolean noBackslashEscapes) @@ -460,27 +500,6 @@ public static String nativeSql(String sql, boolean noBackslashEscapes) throws SQ } } break; - case 'S': - // skip SQL_xxx and SQL_TSI_xxx in functions - // This would convert e.g SQL_INTEGER => INTEGER, SQL_TSI_HOUR=>HOUR - - if (!inQuote && !inComment && inEscapeSeq > 0 - && i + 4 < charArray.length && charArray[i + 1] == 'Q' - && charArray[i + 2] == 'L' && charArray[i + 3] == 'L' - && charArray[i + 4] == '_') { - - if (i + 8 < charArray.length - && charArray[i + 5] == 'T' - && charArray[i + 6] == 'S' - && charArray[i + 7] == 'I' - && charArray[i + 8] == '_') { - i += 8; - continue; - } - i += 4; - continue; - } - break; case '\n': if (inComment && isSlashSlashComment) { // slash-slash and dash-dash comments ends with the end of line @@ -696,7 +715,7 @@ public static String hexdump(int maxQuerySizeToLog, int offset, int length, byte * @param outputBuilder string builder */ private static void writeHex(byte[] bytes, int offset, int dataLength, - StringBuilder outputBuilder) { + StringBuilder outputBuilder) { if (bytes == null || bytes.length == 0) { return; @@ -777,7 +796,7 @@ public static String intToHexString(final int value) { if (b != 0 || nullEnd) { nullEnd = true; hex.append(hexArray[(b & 0xF0) >> 4]) - .append(hexArray[(b & 0x0F)]); + .append(hexArray[(b & 0x0F)]); } } return hex.toString(); @@ -946,16 +965,16 @@ private enum Parse { */ public static boolean validateFileName(String sql, ParameterHolder[] parameters, String fileName) { Pattern pattern = Pattern.compile( - "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+'" + fileName + "'", - Pattern.CASE_INSENSITIVE); + "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+'" + fileName + "'", + Pattern.CASE_INSENSITIVE); if (pattern.matcher(sql).find()) { return true; } if (parameters != null) { pattern = Pattern.compile( - "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+\\?", - Pattern.CASE_INSENSITIVE); + "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+\\?", + Pattern.CASE_INSENSITIVE); if (pattern.matcher(sql).find() && parameters.length > 0) { return parameters[0].toString().toLowerCase().equals("'" + fileName.toLowerCase() + "'"); } diff --git a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java new file mode 100644 index 000000000..59026b863 --- /dev/null +++ b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java @@ -0,0 +1,136 @@ +/* + * + * MariaDB Client for Java + * + * Copyright (c) 2012-2014 Monty Program Ab. + * Copyright (c) 2015-2019 MariaDB Ab. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this library; if not, write to Monty Program Ab info@montyprogram.com. + * + * This particular MariaDB Client for Java file is work + * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to + * the following copyright and notice provisions: + * + * + */ + +package org.mariadb.jdbc; + +import org.junit.Test; + +import java.math.BigInteger; +import java.sql.*; +import java.util.Arrays; + +import static org.junit.Assert.*; + + +public class ScalarFunctionsTest extends BaseTest { + + @Test + public void nativeSQLTest() throws SQLException { + assertEquals( + "SELECT convert(foo(a,b,c), INTEGER)" + + ", convert(convert(?, CHAR), INTEGER)" + + ", convert(?, INTEGER )" + + ", convert(?, INTEGER)" + + ", convert(?, INTEGER )" + + ", convert (?, INTEGER )" + + ", convert(?, INTEGER)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, DOUBLE)" + + ", convert(?, DOUBLE)" + + ", convert(?, DECIMAL)" + + ", convert(?, DECIMAL)" + + ", convert(?, DECIMAL)" + + ", convert(?, DATETIME)" + + ", convert(?, DATETIME)", + sharedConnection.nativeSQL( + "SELECT {fn convert(foo(a,b,c), SQL_BIGINT)}" + + ", {fn convert({fn convert(?, SQL_VARCHAR)}, SQL_BIGINT)}" + + ", {fn convert(?, SQL_BOOLEAN )}" + + ", {fn convert(?, BOOLEAN)}" + + ", {fn convert(?, SMALLINT )}" + + ", {fn convert (?, TINYINT )}" + + ", {fn convert(?, SQL_BIT)}" + + ", {fn convert(?, SQL_BLOB)}" + + ", {fn convert(?, SQL_VARBINARY)}" + + ", {fn convert(?, SQL_LONGVARBINARY)}" + + ", {fn convert(?, SQL_ROWID)}" + + ", {fn convert(?, SQL_BINARY)}" + + ", {fn convert(?, SQL_NCHAR)}" + + ", {fn convert(?, SQL_CLOB)}" + + ", {fn convert(?, SQL_NCLOB)}" + + ", {fn convert(?, SQL_DATALINK)}" + + ", {fn convert(?, SQL_VARCHAR)}" + + ", {fn convert(?, SQL_NVARCHAR)}" + + ", {fn convert(?, SQL_LONGVARCHAR)}" + + ", {fn convert(?, SQL_LONGNVARCHAR)}" + + ", {fn convert(?, SQL_SQLXML)}" + + ", {fn convert(?, SQL_LONGNCHAR)}" + + ", {fn convert(?, SQL_CHAR)}" + + ", {fn convert(?, SQL_FLOAT)}" + + ", {fn convert(?, SQL_DOUBLE)}" + + ", {fn convert(?, SQL_DECIMAL)}" + + ", {fn convert(?, SQL_REAL)}" + + ", {fn convert(?, SQL_NUMERIC)}" + + ", {fn convert(?, SQL_TIMESTAMP)}" + + ", {fn convert(?, SQL_DATETIME)}") + ); + } + + @Test + public void scalarFctTest() throws SQLException { + queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", 2147483648L, 2147483648L); + queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", BigInteger.valueOf(2147483648L), 2147483648L); + queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", 20, 20); + queryScalar("SELECT {fn convert(?, SQL_BOOLEAN)}", true, 1); + queryScalar("SELECT {fn convert(?, SQL_SMALLINT)}", 5000, 5000); + queryScalar("SELECT {fn convert(?, SQL_TINYINT)}", 5000, 5000); + queryScalar("SELECT {fn convert(?, SQL_BIT)}", 255, 255); + queryScalar("SELECT {fn convert(?, SQL_BINARY)}", "test", "test".getBytes()); + queryScalar("SELECT {fn convert(?, SQL_DATETIME)}", "2020-12-31 12:13.15.12", new Timestamp(2020 - 1900, 11, 31, 12, 13, 15, 0)); + } + + private void queryScalar(String sql, Object val, Object res) throws SQLException { + try (PreparedStatement prep = sharedConnection.prepareStatement(sql)) { + prep.setObject(1, val); + ResultSet rs = prep.executeQuery(); + assertTrue(rs.next()); + Object obj = rs.getObject(1); + if (obj instanceof byte[]) { + byte[] arr = (byte[]) obj ; + assertArrayEquals((byte[]) res, arr); + } else { + assertEquals(res, rs.getObject(1)); + } + } + } + +} From f22fe19bcce6ce9814b2ecae7f11554da1195665 Mon Sep 17 00:00:00 2001 From: rusher Date: Tue, 30 Jul 2019 16:07:03 +0200 Subject: [PATCH 12/19] [CONJ-722] add option blankTableNameMeta that force result-set metadata getTableName method to empty value. This is mainly for Oracle compatibility. --- .../use-mariadb-connector-j-driver.creole | 1 + .../mariadb/jdbc/MariaDbDatabaseMetaData.java | 2 +- .../jdbc/MariaDbResultSetMetaData.java | 121 +-- .../jdbc/ServerSidePreparedStatement.java | 34 +- .../com/read/resultset/SelectResultSet.java | 47 +- .../jdbc/internal/util/DefaultOptions.java | 807 ++++++++++++------ .../mariadb/jdbc/internal/util/Options.java | 120 +-- .../mariadb/jdbc/ResultSetMetaDataTest.java | 53 +- 8 files changed, 666 insertions(+), 519 deletions(-) diff --git a/documentation/use-mariadb-connector-j-driver.creole b/documentation/use-mariadb-connector-j-driver.creole index d327ae4db..1bab41368 100644 --- a/documentation/use-mariadb-connector-j-driver.creole +++ b/documentation/use-mariadb-connector-j-driver.creole @@ -187,6 +187,7 @@ See [[use-mariadb-connector-j-driver.creole#using-pooling|using pooling]] for mo |=useAffectedRows|default correspond to the JDBC standard, reporting real affected rows. if enable, will report "affected" rows. example : if enable, an update command that doesn't change a row value will still be "affected", then report.\\//Default: false. Since 2.2.6// |=includeInnodbStatusInDeadlockExceptions|add "SHOW ENGINE INNODB STATUS" result to exception trace when having a deadlock exception\\//Default: false. Since 2.3.0// |=includeThreadDumpInDeadlockExceptions|add thread dump to exception trace when having a deadlock exception\\//Default: false. Since 2.3.0// +|=blankTableNameMeta|Result-set metadata getTableName always return blank. This option is mainly for ORACLE db compatibility\\//Default: false. Since 2.4.3// \\\\ == Failover/High availability URL parameters diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java index ad9024428..632f212a9 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java @@ -472,7 +472,7 @@ private ResultSet executeQuery(String sql) throws SQLException { ResultSet.CONCUR_READ_ONLY); SelectResultSet rs = (SelectResultSet) stmt.executeQuery(sql); rs.setStatement(null); // bypass Hibernate statement tracking (CONJ-49) - rs.setReturnTableAlias(true); + rs.setForceTableAlias(); return rs; } diff --git a/src/main/java/org/mariadb/jdbc/MariaDbResultSetMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbResultSetMetaData.java index 396220609..330f9327f 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbResultSetMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbResultSetMetaData.java @@ -3,7 +3,7 @@ * MariaDB Client for Java * * Copyright (c) 2012-2014 Monty Program Ab. - * Copyright (c) 2015-2017 MariaDB Ab. + * Copyright (c) 2015-2019 MariaDB Ab. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -18,36 +18,6 @@ * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to Monty Program Ab info@montyprogram.com. * - * This particular MariaDB Client for Java file is work - * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to - * the following copyright and notice provisions: - * - * Copyright (c) 2009-2011, Marcus Eriksson - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * Neither the name of the driver nor the names of its contributors may not be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * */ package org.mariadb.jdbc; @@ -61,25 +31,24 @@ import org.mariadb.jdbc.internal.util.constant.ColumnFlags; import org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper; - public class MariaDbResultSetMetaData implements ResultSetMetaData { private final ColumnInformation[] fieldPackets; private final Options options; - private final boolean returnTableAlias; + private final boolean forceAlias; /** * Constructor. * - * @param fieldPackets column informations - * @param options connection options - * @param returnTableAlias must return table alias or real table name + * @param fieldPackets column informations + * @param options connection options + * @param forceAlias force table and column name alias as original data */ - public MariaDbResultSetMetaData(ColumnInformation[] fieldPackets, Options options, - boolean returnTableAlias) { + public MariaDbResultSetMetaData( + final ColumnInformation[] fieldPackets, final Options options, final boolean forceAlias) { this.fieldPackets = fieldPackets; this.options = options; - this.returnTableAlias = returnTableAlias; + this.forceAlias = forceAlias; } /** @@ -137,8 +106,8 @@ public boolean isCurrency(final int column) { * Indicates the nullability of values in the designated column. * * @param column the first column is 1, the second is 2, ... - * @return the nullability status of the given column; one of columnNoNulls, - * columnNullable or columnNullableUnknown + * @return the nullability status of the given column; one of columnNoNulls, + * columnNullable or columnNullableUnknown * @throws SQLException if a database access error occurs */ public int isNullable(final int column) throws SQLException { @@ -173,10 +142,9 @@ public int getColumnDisplaySize(final int column) throws SQLException { /** * Gets the designated column's suggested title for use in printouts and displays. The suggested - * title is usually specified by the SQL AS clause. If a SQL AS is not - * specified, the value returned from - * getColumnLabel will be the same as the value returned by the - * getColumnName method. + * title is usually specified by the SQL AS clause. If a SQL AS is not + * specified, the value returned from getColumnLabel will be the same as the value + * returned by the getColumnName method. * * @param column the first column is 1, the second is 2, ... * @return the suggested column title @@ -195,13 +163,8 @@ public String getColumnLabel(final int column) throws SQLException { */ public String getColumnName(final int column) throws SQLException { String columnName = getColumnInformation(column).getOriginalName(); - if (returnTableAlias) { - columnName = getColumnInformation(column).getName(); //for old mysql compatibility - } - - if ("".equals(columnName)) { - // odd things that are no columns, e.g count(*) - columnName = getColumnLabel(column); + if ("".equals(columnName) || options.useOldAliasMetadataBehavior || forceAlias) { + return getColumnLabel(column); } return columnName; } @@ -219,7 +182,7 @@ public String getCatalogName(int column) throws SQLException { /** * Get the designated column's specified column size. For numeric data, this is the maximum - * precision. For character data, this is the length in characters. For datetime datatypes, this + * precision. For character data, this is the length in characters. For datetime datatypes, this * is the length in characters of the String representation (assuming the maximum allowed * precision of the fractional seconds component). For binary data, this is the length in bytes. * For the ROWID datatype, this is the length in bytes. 0 is returned for data types where the @@ -253,13 +216,19 @@ public int getScale(final int column) throws SQLException { * @throws SQLException if a database access error occurs */ public String getTableName(final int column) throws SQLException { - if (returnTableAlias) { + if (forceAlias) { return getColumnInformation(column).getTable(); - } else { - return getColumnInformation(column).getOriginalTable(); } - } + if (options.blankTableNameMeta) { + return ""; + } + + if (options.useOldAliasMetadataBehavior) { + return getColumnInformation(column).getTable(); + } + return getColumnInformation(column).getOriginalTable(); + } public String getSchemaName(int column) { return ""; @@ -313,7 +282,6 @@ public int getColumnType(final int column) throws SQLException { default: return ci.getColumnType().getSqlType(); } - } /** @@ -326,9 +294,8 @@ public int getColumnType(final int column) throws SQLException { */ public String getColumnTypeName(final int column) throws SQLException { ColumnInformation ci = getColumnInformation(column); - return ColumnType - .getColumnTypeName(ci.getColumnType(), ci.getLength(), ci.isSigned(), ci.isBinary()); - + return ColumnType.getColumnTypeName( + ci.getColumnType(), ci.getLength(), ci.isSigned(), ci.isBinary()); } /** @@ -363,10 +330,8 @@ public boolean isDefinitelyWritable(final int column) { /** * Returns the fully-qualified name of the Java class whose instances are manufactured if the - * method - * ResultSet.getObject is called to retrieve a value from the column. - * ResultSet.getObject - * may return a subclass of the class returned by this method. + * method ResultSet.getObject is called to retrieve a value from the column. + * ResultSet.getObject may return a subclass of the class returned by this method. * * @param column the first column is 1, the second is 2, ... * @return the fully-qualified name of the class in the Java programming language that would be @@ -374,12 +339,11 @@ public boolean isDefinitelyWritable(final int column) { * column. This is the class name used for custom mapping. * @throws SQLException if a database access error occurs */ - public String getColumnClassName(int column) throws SQLException { ColumnInformation ci = getColumnInformation(column); ColumnType type = ci.getColumnType(); - return ColumnType - .getClassName(type, (int) ci.getLength(), ci.isSigned(), ci.isBinary(), options); + return ColumnType.getClassName( + type, (int) ci.getLength(), ci.isSigned(), ci.isBinary(), options); } private ColumnInformation getColumnInformation(int column) throws SQLException { @@ -391,14 +355,13 @@ private ColumnInformation getColumnInformation(int column) throws SQLException { /** * Returns an object that implements the given interface to allow access to non-standard methods, - * or standard methods not exposed by the proxy. - *
+ * or standard methods not exposed by the proxy.
* If the receiver implements the interface then the result is the receiver or a proxy for the * receiver. If the receiver is a wrapper and the wrapped object implements the interface then the * result is the wrapped object or a proxy for the wrapped object. Otherwise return the the result * of calling unwrap recursively on the wrapped object or a proxy for that result. If - * the receiver is not a wrapper and does not implement the interface, then an - * SQLException is thrown. + * the receiver is not a wrapper and does not implement the interface, then an SQLException + * is thrown. * * @param iface A Class defining an interface that the result must implement. * @return an object that implements the interface. May be a proxy for the actual implementing @@ -420,18 +383,18 @@ public T unwrap(final Class iface) throws SQLException { /** * Returns true if this either implements the interface argument or is directly or indirectly a * wrapper for an object that does. Returns false otherwise. If this implements the interface then - * return true, else if this is a wrapper then return the result of recursively calling - * isWrapperFor on the wrapped object. If this does not implement the interface and - * is not a wrapper, return false. This method should be implemented as a low-cost operation - * compared to unwrap so that callers can use this method to avoid expensive - * unwrap calls that may fail. If this method returns true then calling - * unwrap with the same argument should succeed. + * return true, else if this is a wrapper then return the result of recursively calling + * isWrapperFor on the wrapped object. If this does not implement the interface and is not + * a wrapper, return false. This method should be implemented as a low-cost operation compared to + * unwrap so that callers can use this method to avoid expensive unwrap + * calls that may fail. If this method returns true then calling unwrap with the same + * argument should succeed. * * @param iface a Class defining an interface. * @return true if this implements the interface or directly or indirectly wraps an object that * does. * @throws SQLException if an error occurs while determining whether this is a wrapper for an - * object with the given interface. + * object with the given interface. */ public boolean isWrapperFor(final Class iface) throws SQLException { return iface.isInstance(this); diff --git a/src/main/java/org/mariadb/jdbc/ServerSidePreparedStatement.java b/src/main/java/org/mariadb/jdbc/ServerSidePreparedStatement.java index 8f63a2b73..2e379ff31 100644 --- a/src/main/java/org/mariadb/jdbc/ServerSidePreparedStatement.java +++ b/src/main/java/org/mariadb/jdbc/ServerSidePreparedStatement.java @@ -18,36 +18,6 @@ * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to Monty Program Ab info@montyprogram.com. * - * This particular MariaDB Client for Java file is work - * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to - * the following copyright and notice provisions: - * - * Copyright (c) 2009-2011, Marcus Eriksson - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * Neither the name of the driver nor the names of its contributors may not be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * */ package org.mariadb.jdbc; @@ -79,7 +49,6 @@ public class ServerSidePreparedStatement extends BasePrepareStatement implements protected int parameterCount = -1; private String sql; private ServerPrepareResult serverPrepareResult = null; - private boolean returnTableAlias = false; private MariaDbResultSetMetaData metadata; private MariaDbParameterMetaData parameterMetaData; private Map currentParameterHolder; @@ -110,7 +79,6 @@ public ServerSidePreparedStatement(MariaDbConnection connection, String sql, throws SQLException { super(connection, resultSetScrollType, resultSetConcurrency, autoGeneratedKeys); this.sql = sql; - returnTableAlias = options.useOldAliasMetadataBehavior; currentParameterHolder = Collections.synchronizedMap(new TreeMap()); mustExecuteOnMaster = protocol.isMasterConnection(); prepare(this.sql); @@ -157,7 +125,7 @@ private void prepare(String sql) throws SQLException { private void setMetaFromResult() { parameterCount = serverPrepareResult.getParameters().length; metadata = new MariaDbResultSetMetaData(serverPrepareResult.getColumns(), - protocol.getUrlParser().getOptions(), returnTableAlias); + protocol.getUrlParser().getOptions(), false); parameterMetaData = new MariaDbParameterMetaData(serverPrepareResult.getParameters()); } diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java index 068d07e01..9d0624103 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/resultset/SelectResultSet.java @@ -3,7 +3,7 @@ * MariaDB Client for Java * * Copyright (c) 2012-2014 Monty Program Ab. - * Copyright (c) 2015-2017 MariaDB Ab. + * Copyright (c) 2015-2019 MariaDB Ab. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -18,36 +18,6 @@ * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to Monty Program Ab info@montyprogram.com. * - * This particular MariaDB Client for Java file is work - * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to - * the following copyright and notice provisions: - * - * Copyright (c) 2009-2011, Marcus Eriksson - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * Neither the name of the driver nor the names of its contributors may not be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * */ @@ -152,11 +122,10 @@ public class SelectResultSet implements ResultSet { private int rowPointer; private ColumnNameMap columnNameMap; private int lastRowPointer = -1; - private int dataTypeMappingFlags; - private boolean returnTableAlias; private boolean isClosed; private boolean eofDeprecated; private ReentrantLock lock; + private boolean forceAlias; /** * Create Streaming resultSet. @@ -178,7 +147,6 @@ public SelectResultSet(ColumnInformation[] columnInformation, Results results, P this.protocol = protocol; this.options = protocol.getOptions(); this.noBackslashEscapes = protocol.noBackslashEscapes(); - this.returnTableAlias = this.options.useOldAliasMetadataBehavior; this.columnsInformation = columnInformation; this.columnNameMap = new ColumnNameMap(columnsInformation); @@ -234,11 +202,9 @@ public SelectResultSet(ColumnInformation[] columnInformation, List resul if (protocol != null) { this.options = protocol.getOptions(); this.timeZone = protocol.getTimeZone(); - this.returnTableAlias = this.options.useOldAliasMetadataBehavior; } else { this.options = new Options(); this.timeZone = TimeZone.getDefault(); - this.returnTableAlias = false; } this.row = new TextRowProtocol(0, this.options); this.protocol = null; @@ -1282,7 +1248,7 @@ public String getCursorName() throws SQLException { * {inheritDoc}. */ public ResultSetMetaData getMetaData() { - return new MariaDbResultSetMetaData(columnsInformation, options, returnTableAlias); + return new MariaDbResultSetMetaData(columnsInformation, options, forceAlias); } /** @@ -2395,8 +2361,11 @@ public boolean isWrapperFor(final Class iface) throws SQLException { return iface.isInstance(this); } - public void setReturnTableAlias(boolean returnTableAlias) { - this.returnTableAlias = returnTableAlias; + /** + * Force metadata getTableName to return table alias, not original table name. + */ + public void setForceTableAlias() { + this.forceAlias = true; } private void rangeCheck(Object className, long minValue, long maxValue, long value, diff --git a/src/main/java/org/mariadb/jdbc/internal/util/DefaultOptions.java b/src/main/java/org/mariadb/jdbc/internal/util/DefaultOptions.java index dd8eebf5b..8ff7bc344 100755 --- a/src/main/java/org/mariadb/jdbc/internal/util/DefaultOptions.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/DefaultOptions.java @@ -18,36 +18,6 @@ * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to Monty Program Ab info@montyprogram.com. * - * This particular MariaDB Client for Java file is work - * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to - * the following copyright and notice provisions: - * - * Copyright (c) 2009-2011, Marcus Eriksson - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * Neither the name of the driver nor the names of its contributors may not be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * */ package org.mariadb.jdbc.internal.util; @@ -57,7 +27,6 @@ import org.mariadb.jdbc.internal.util.constant.HaMode; public enum DefaultOptions { - USER("user", "1.0.0", "Database user name", false), PASSWORD("password", "1.0.0", "Password of database user", false), @@ -65,25 +34,49 @@ public enum DefaultOptions { * The connect timeout value, in milliseconds, or zero for no timeout. Default: 30000 (30 seconds) * (was 0 before 2.1.2) */ - CONNECT_TIMEOUT("connectTimeout", 30_000, 0, "1.1.8", - "The connect timeout value, in milliseconds, or zero for no timeout.", false), + CONNECT_TIMEOUT( + "connectTimeout", + 30_000, + 0, + "1.1.8", + "The connect timeout value, in milliseconds, or zero for no timeout.", + false), PIPE("pipe", "1.1.3", "On Windows, specify named pipe name to connect.", false), - LOCAL_SOCKET("localSocket", "1.1.4", - "Permits connecting to the database via Unix domain socket, if the server " - + "allows it. \nThe value is the path of Unix domain socket (i.e \"socket\" database parameter : " - + "select @@socket).", false), - SHARED_MEMORY("sharedMemory", "1.1.4", + LOCAL_SOCKET( + "localSocket", + "1.1.4", + "Permits connecting to the database via Unix domain socket, if the server allows it." + + " \nThe value is the path of Unix domain socket (i.e \"socket\" database parameter : " + + "select @@socket).", + false), + SHARED_MEMORY( + "sharedMemory", + "1.1.4", "Permits connecting to the database via shared memory, if the server allows " - + "it. \nThe value is the base name of the shared memory.", false), - TCP_NO_DELAY("tcpNoDelay", Boolean.TRUE, "1.0.0", - "Sets corresponding option on the connection socket.", false), - TCP_ABORTIVE_CLOSE("tcpAbortiveClose", Boolean.FALSE, "1.1.1", - "Sets corresponding option on the connection " - + "socket.", false), - LOCAL_SOCKET_ADDRESS("localSocketAddress", "1.1.8", - "Hostname or IP address to bind the connection socket to a " - + "local (UNIX domain) socket.", false), - SOCKET_TIMEOUT("socketTimeout", new Integer[]{10000, null, null, null, null, null}, 0, "1.1.8", + + "it. \nThe value is the base name of the shared memory.", + false), + TCP_NO_DELAY( + "tcpNoDelay", + Boolean.TRUE, + "1.0.0", + "Sets corresponding option on the connection socket.", + false), + TCP_ABORTIVE_CLOSE( + "tcpAbortiveClose", + Boolean.FALSE, + "1.1.1", + "Sets corresponding option on the connection " + "socket.", + false), + LOCAL_SOCKET_ADDRESS( + "localSocketAddress", + "1.1.8", + "Hostname or IP address to bind the connection socket to a " + "local (UNIX domain) socket.", + false), + SOCKET_TIMEOUT( + "socketTimeout", + new Integer[] {10000, null, null, null, null, null}, + 0, + "1.1.8", "Defined the " + "network socket timeout (SO_TIMEOUT) in milliseconds. Value of 0 disables this timeout. \n" + "If the goal is to set a timeout for all queries, since MariaDB 10.1.1, the server has permitted a " @@ -91,45 +84,87 @@ public enum DefaultOptions { + " the connection then is still usable.\n" + "Default: 0 (standard configuration) or 10000ms (using \"aurora\" failover configuration).", false), - INTERACTIVE_CLIENT("interactiveClient", Boolean.FALSE, "1.1.8", + INTERACTIVE_CLIENT( + "interactiveClient", + Boolean.FALSE, + "1.1.8", "Session timeout is defined by the wait_timeout " + "server variable. Setting interactiveClient to true will tell the server to use the interactive_timeout " - + "server variable.", false), - DUMP_QUERY_ON_EXCEPTION("dumpQueriesOnException", Boolean.FALSE, "1.1.0", + + "server variable.", + false), + DUMP_QUERY_ON_EXCEPTION( + "dumpQueriesOnException", + Boolean.FALSE, + "1.1.0", "If set to 'true', an exception is thrown " - + "during query execution containing a query string.", false), - USE_OLD_ALIAS_METADATA_BEHAVIOR("useOldAliasMetadataBehavior", Boolean.FALSE, "1.1.9", + + "during query execution containing a query string.", + false), + USE_OLD_ALIAS_METADATA_BEHAVIOR( + "useOldAliasMetadataBehavior", + Boolean.FALSE, + "1.1.9", "Metadata ResultSetMetaData.getTableName() returns the physical table name. \"useOldAliasMetadataBehavior\"" - + " permits activating the legacy code that sends the table alias if set.", false), - ALLOW_LOCAL_INFILE("allowLocalInfile", Boolean.TRUE, "1.2.1", "Permit loading data from file", + + " permits activating the legacy code that sends the table alias if set.", false), - SESSION_VARIABLES("sessionVariables", "1.1.0", + ALLOW_LOCAL_INFILE( + "allowLocalInfile", Boolean.TRUE, "1.2.1", "Permit loading data from file", false), + SESSION_VARIABLES( + "sessionVariables", + "1.1.0", "= pairs separated by comma, mysql session variables, " - + "set upon establishing successful connection.", false), - CREATE_DATABASE_IF_NOT_EXISTS("createDatabaseIfNotExist", Boolean.FALSE, "1.1.8", - "the specified database in the " - + "url will be created if non-existent.", false), - SERVER_TIMEZONE("serverTimezone", "1.1.8", "Defines the server time zone.\n" - + "to use only if the jre server has a different time implementation of the server.\n" - + "(best to have the same server time zone when possible).", false), - NULL_CATALOG_MEANS_CURRENT("nullCatalogMeansCurrent", Boolean.TRUE, "1.1.8", - "DatabaseMetaData use current catalog" - + " if null.", false), - TINY_INT_IS_BIT("tinyInt1isBit", Boolean.TRUE, "1.0.0", + + "set upon establishing successful connection.", + false), + CREATE_DATABASE_IF_NOT_EXISTS( + "createDatabaseIfNotExist", + Boolean.FALSE, + "1.1.8", + "the specified database in the " + "url will be created if non-existent.", + false), + SERVER_TIMEZONE( + "serverTimezone", + "1.1.8", + "Defines the server time zone.\n" + + "to use only if the jre server has a different time implementation of the server.\n" + + "(best to have the same server time zone when possible).", + false), + NULL_CATALOG_MEANS_CURRENT( + "nullCatalogMeansCurrent", + Boolean.TRUE, + "1.1.8", + "DatabaseMetaData use current catalog" + " if null.", + false), + TINY_INT_IS_BIT( + "tinyInt1isBit", + Boolean.TRUE, + "1.0.0", "Datatype mapping flag, handle Tiny as BIT(boolean).", false), - YEAR_IS_DATE_TYPE("yearIsDateType", Boolean.TRUE, "1.0.0", - "Year is date type, rather than numerical.", false), - USE_SSL("useSsl", Boolean.FALSE, "1.1.0", "Force SSL on connection. (legacy alias \"useSSL\")", + YEAR_IS_DATE_TYPE( + "yearIsDateType", Boolean.TRUE, "1.0.0", "Year is date type, rather than numerical.", false), + USE_SSL( + "useSsl", + Boolean.FALSE, + "1.1.0", + "Force SSL on connection. (legacy alias \"useSSL\")", false), - USER_COMPRESSION("useCompression", Boolean.FALSE, "1.0.0", + USER_COMPRESSION( + "useCompression", + Boolean.FALSE, + "1.0.0", "Compresses the exchange with the database through gzip." + " This permits better performance when the database is not in the same location.", false), - ALLOW_MULTI_QUERIES("allowMultiQueries", Boolean.FALSE, "1.0.0", + ALLOW_MULTI_QUERIES( + "allowMultiQueries", + Boolean.FALSE, + "1.0.0", "permit multi-queries like insert into ab (i) " - + "values (1); insert into ab (i) values (2).", false), - REWRITE_BATCHED_STATEMENTS("rewriteBatchedStatements", Boolean.FALSE, "1.1.8", + + "values (1); insert into ab (i) values (2).", + false), + REWRITE_BATCHED_STATEMENTS( + "rewriteBatchedStatements", + Boolean.FALSE, + "1.1.8", "For insert queries, rewrite " + "batchedStatement to execute in a single executeQuery.\n" + "example:\n" @@ -141,22 +176,45 @@ public enum DefaultOptions { + "INSERT INTO TABLE(col1) VALUES (1) ON DUPLICATE KEY UPDATE col2=2;INSERT INTO TABLE(col1) VALUES (3) ON " + "DUPLICATE KEY UPDATE col2=4\n" + "\n" - + "when active, the useServerPrepStmts option is set to false", false), - TCP_KEEP_ALIVE("tcpKeepAlive", Boolean.TRUE, "1.0.0", - "Sets corresponding option on the connection socket.", false), - TCP_RCV_BUF("tcpRcvBuf", (Integer) null, 0, "1.0.0", - "set buffer size for TCP buffer (SO_RCVBUF).", false), - TCP_SND_BUF("tcpSndBuf", (Integer) null, 0, "1.0.0", - "set buffer size for TCP buffer (SO_SNDBUF).", false), - SOCKET_FACTORY("socketFactory", "1.0.0", + + "when active, the useServerPrepStmts option is set to false", + false), + TCP_KEEP_ALIVE( + "tcpKeepAlive", + Boolean.TRUE, + "1.0.0", + "Sets corresponding option on the connection socket.", + false), + TCP_RCV_BUF( + "tcpRcvBuf", + (Integer) null, + 0, + "1.0.0", + "set buffer size for TCP buffer (SO_RCVBUF).", + false), + TCP_SND_BUF( + "tcpSndBuf", + (Integer) null, + 0, + "1.0.0", + "set buffer size for TCP buffer (SO_SNDBUF).", + false), + SOCKET_FACTORY( + "socketFactory", + "1.0.0", "to use a custom socket factory, set it to the full name of the class that" - + " implements javax.net.SocketFactory.", false), - PIN_GLOBAL_TX_TO_PHYSICAL_CONNECTION("pinGlobalTxToPhysicalConnection", Boolean.FALSE, "1.1.8", - "", false), - TRUST_SERVER_CERTIFICATE("trustServerCertificate", Boolean.FALSE, "1.1.1", - "When using SSL, do not check server's" - + " certificate.", false), - SERVER_SSL_CERT("serverSslCert", "1.1.3", + + " implements javax.net.SocketFactory.", + false), + PIN_GLOBAL_TX_TO_PHYSICAL_CONNECTION( + "pinGlobalTxToPhysicalConnection", Boolean.FALSE, "1.1.8", "", false), + TRUST_SERVER_CERTIFICATE( + "trustServerCertificate", + Boolean.FALSE, + "1.1.1", + "When using SSL, do not check server's" + " certificate.", + false), + SERVER_SSL_CERT( + "serverSslCert", + "1.1.3", "Permits providing server's certificate in DER form, or server's CA" + " certificate. The server will be added to trustStor. This permits a self-signed certificate to be trusted.\n" + "Can be used in one of 3 forms : \n" @@ -164,112 +222,207 @@ public enum DefaultOptions { + "* serverSslCert=classpath:relative/cert.pem (relative to current classpath)\n" + "* or as verbatim DER-encoded certificate string \"------BEGIN CERTIFICATE-----\" .", false), - USE_FRACTIONAL_SECONDS("useFractionalSeconds", Boolean.TRUE, "1.0.0", + USE_FRACTIONAL_SECONDS( + "useFractionalSeconds", + Boolean.TRUE, + "1.0.0", "Correctly handle subsecond precision in" + " timestamps (feature available with MariaDB 5.3 and later).\n" - + "May confuse 3rd party components (Hibernate).", false), - AUTO_RECONNECT("autoReconnect", Boolean.FALSE, "1.2.0", - "Driver must recreateConnection after a failover.", false), - FAIL_ON_READ_ONLY("failOnReadOnly", Boolean.FALSE, "1.2.0", + + "May confuse 3rd party components (Hibernate).", + false), + AUTO_RECONNECT( + "autoReconnect", + Boolean.FALSE, + "1.2.0", + "Driver must recreateConnection after a failover.", + false), + FAIL_ON_READ_ONLY( + "failOnReadOnly", + Boolean.FALSE, + "1.2.0", "After a master failover and no other master found," - + " back on a read-only host ( throw exception if not).", false), - RETRY_ALL_DOWN("retriesAllDown", 120, 0, "1.2.0", + + " back on a read-only host ( throw exception if not).", + false), + RETRY_ALL_DOWN( + "retriesAllDown", + 120, + 0, + "1.2.0", "When using loadbalancing, the number of times the driver should" + " cycle through available hosts, attempting to connect.\n" + " * Between cycles, the driver will pause for 250ms if no servers are available.", false), - FAILOVER_LOOP_RETRIES("failoverLoopRetries", 120, 0, "1.2.0", + FAILOVER_LOOP_RETRIES( + "failoverLoopRetries", + 120, + 0, + "1.2.0", "When using failover, the number of times the driver" + " should cycle silently through available hosts, attempting to connect.\n" + " * Between cycles, the driver will pause for 250ms if no servers are available.\n" - + " * if set to 0, there will be no silent reconnection", false), - VALID_CONNECTION_TIMEOUT("validConnectionTimeout", 0, 0, "1.2.0", + + " * if set to 0, there will be no silent reconnection", + false), + VALID_CONNECTION_TIMEOUT( + "validConnectionTimeout", + 0, + 0, + "1.2.0", "When in multiple hosts, after this time in" + " second without used, verification that the connections haven't been lost.\n" + " * When 0, no verification will be done. Defaults to 0 (120 before 1.5.8 version)", false), - LOAD_BALANCE_BLACKLIST_TIMEOUT("loadBalanceBlacklistTimeout", 50, 0, "1.2.0", - "time in second a server is" - + " blacklisted after a connection failure.", false), - CACHE_PREP_STMTS("cachePrepStmts", Boolean.TRUE, "1.3.0", + LOAD_BALANCE_BLACKLIST_TIMEOUT( + "loadBalanceBlacklistTimeout", + 50, + 0, + "1.2.0", + "time in second a server is" + " blacklisted after a connection failure.", + false), + CACHE_PREP_STMTS( + "cachePrepStmts", + Boolean.TRUE, + "1.3.0", "enable/disable prepare Statement cache, default true.", false), - PREP_STMT_CACHE_SIZE("prepStmtCacheSize", 250, 0, "1.3.0", + PREP_STMT_CACHE_SIZE( + "prepStmtCacheSize", + 250, + 0, + "1.3.0", "This sets the number of prepared statements that the " - + "driver will cache per connection if \"cachePrepStmts\" is enabled.", false), - PREP_STMT_CACHE_SQL_LIMIT("prepStmtCacheSqlLimit", 2048, 0, "1.3.0", + + "driver will cache per connection if \"cachePrepStmts\" is enabled.", + false), + PREP_STMT_CACHE_SQL_LIMIT( + "prepStmtCacheSqlLimit", + 2048, + 0, + "1.3.0", "This is the maximum length of a prepared SQL" - + " statement that the driver will cache if \"cachePrepStmts\" is enabled.", false), - ASSURE_READONLY("assureReadOnly", Boolean.FALSE, "1.3.0", + + " statement that the driver will cache if \"cachePrepStmts\" is enabled.", + false), + ASSURE_READONLY( + "assureReadOnly", + Boolean.FALSE, + "1.3.0", "If true, in high availability, and switching to a " + "read-only host, assure that this host is in read-only mode by setting the session to read-only.", false), - USE_LEGACY_DATETIME_CODE("useLegacyDatetimeCode", Boolean.TRUE, "1.3.0", + USE_LEGACY_DATETIME_CODE( + "useLegacyDatetimeCode", + Boolean.TRUE, + "1.3.0", "if true (default) store date/timestamps " + "according to client time zone.\n" + "if false, store all date/timestamps in DB according to server time zone, and time information (that is a" + " time difference), doesn't take\n" - + "timezone in account.", false), - MAXIMIZE_MYSQL_COMPATIBILITY("maximizeMysqlCompatibility", Boolean.FALSE, "1.3.0", + + "timezone in account.", + false), + MAXIMIZE_MYSQL_COMPATIBILITY( + "maximizeMysqlCompatibility", + Boolean.FALSE, + "1.3.0", "maximize MySQL compatibility.\n" + "when using jdbc setDate(), will store date in client timezone, not in server timezone when " + "useLegacyDatetimeCode = false.\n" - + "default to false.", false), - USE_SERVER_PREP_STMTS("useServerPrepStmts", Boolean.FALSE, "1.3.0", + + "default to false.", + false), + USE_SERVER_PREP_STMTS( + "useServerPrepStmts", + Boolean.FALSE, + "1.3.0", "useServerPrepStmts must prepared statements be" + " prepared on server side, or just faked on client side.\n" + " * if rewriteBatchedStatements is set to true, this options will be set to false.", false), - TRUSTSTORE("trustStore", "1.3.0", + TRUSTSTORE( + "trustStore", + "1.3.0", "File path of the trustStore file (similar to java System property " + "\"javax.net.ssl.trustStore\"). (legacy alias trustCertificateKeyStoreUrl)\n" + "Use the specified file for trusted root certificates.\n" - + "When set, overrides serverSslCert.", false), - TRUST_CERTIFICATE_KEYSTORE_PASSWORD("trustStorePassword", "1.3.0", + + "When set, overrides serverSslCert.", + false), + TRUST_CERTIFICATE_KEYSTORE_PASSWORD( + "trustStorePassword", + "1.3.0", "Password for the trusted root certificate file" + " (similar to java System property \"javax.net.ssl.trustStorePassword\").\n" - + "(legacy alias trustCertificateKeyStorePassword).", false), - KEYSTORE("keyStore", "1.3.0", + + "(legacy alias trustCertificateKeyStorePassword).", + false), + KEYSTORE( + "keyStore", + "1.3.0", "File path of the keyStore file that contain client private key store and associate " + "certificates (similar to java System property \"javax.net.ssl.keyStore\", but ensure that only the " - + "private key's entries are used).(legacy alias clientCertificateKeyStoreUrl).", false), - KEYSTORE_PASSWORD("keyStorePassword", "1.3.0", + + "private key's entries are used).(legacy alias clientCertificateKeyStoreUrl).", + false), + KEYSTORE_PASSWORD( + "keyStorePassword", + "1.3.0", "Password for the client certificate keyStore (similar to java " + "System property \"javax.net.ssl.keyStorePassword\").(legacy alias clientCertificateKeyStorePassword)", false), - PRIVATE_KEYS_PASSWORD("keyPassword", "1.5.3", + PRIVATE_KEYS_PASSWORD( + "keyPassword", + "1.5.3", "Password for the private key in client certificate keyStore. (only " - + "needed if private key password differ from keyStore password).", false), - ENABLED_SSL_PROTOCOL_SUITES("enabledSslProtocolSuites", "1.5.0", + + "needed if private key password differ from keyStore password).", + false), + ENABLED_SSL_PROTOCOL_SUITES( + "enabledSslProtocolSuites", + "1.5.0", "Force TLS/SSL protocol to a specific set of TLS " + "versions (comma separated list). \n" + "Example : \"TLSv1, TLSv1.1, TLSv1.2\"\n" - + "(Alias \"enabledSSLProtocolSuites\" works too)", false), - ENABLED_SSL_CIPHER_SUITES("enabledSslCipherSuites", "1.5.0", + + "(Alias \"enabledSSLProtocolSuites\" works too)", + false), + ENABLED_SSL_CIPHER_SUITES( + "enabledSslCipherSuites", + "1.5.0", "Force TLS/SSL cipher (comma separated list).\n" + "Example : \"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384\"", false), - CONTINUE_BATCH_ON_ERROR("continueBatchOnError", Boolean.TRUE, "1.4.0", - "When executing batch queries, must batch " - + "continue on error.", false), - JDBC_COMPLIANT_TRUNCATION("jdbcCompliantTruncation", Boolean.TRUE, "1.4.0", + CONTINUE_BATCH_ON_ERROR( + "continueBatchOnError", + Boolean.TRUE, + "1.4.0", + "When executing batch queries, must batch " + "continue on error.", + false), + JDBC_COMPLIANT_TRUNCATION( + "jdbcCompliantTruncation", + Boolean.TRUE, + "1.4.0", "Truncation error (\"Data truncated for" + " column '%' at row %\", \"Out of range value for column '%' at row %\") will be thrown as error, and not as warning.", false), - CACHE_CALLABLE_STMTS("cacheCallableStmts", Boolean.TRUE, "1.4.0", - "enable/disable callable Statement cache, default" - + " true.", false), - CALLABLE_STMT_CACHE_SIZE("callableStmtCacheSize", 150, 0, "1.4.0", + CACHE_CALLABLE_STMTS( + "cacheCallableStmts", + Boolean.TRUE, + "1.4.0", + "enable/disable callable Statement cache, default" + " true.", + false), + CALLABLE_STMT_CACHE_SIZE( + "callableStmtCacheSize", + 150, + 0, + "1.4.0", "This sets the number of callable statements " - + "that the driver will cache per VM if \"cacheCallableStmts\" is enabled.", false), - CONNECTION_ATTRIBUTES("connectionAttributes", "1.4.0", + + "that the driver will cache per VM if \"cacheCallableStmts\" is enabled.", + false), + CONNECTION_ATTRIBUTES( + "connectionAttributes", + "1.4.0", "When performance_schema is active, permit to send server " + "some client information in a key;value pair format " + "(example: connectionAttributes=key1:value1,key2,value2).\n" + "Those informations can be retrieved on server within tables performance_schema.session_connect_attrs " + "and performance_schema.session_account_connect_attrs.\n" - + "This can permit from server an identification of client/application", false), - USE_BATCH_MULTI_SEND("useBatchMultiSend", (Boolean) null, "1.5.0", + + "This can permit from server an identification of client/application", + false), + USE_BATCH_MULTI_SEND( + "useBatchMultiSend", + (Boolean) null, + "1.5.0", "*Not compatible with aurora*\n" + "Driver will can send queries by batch. \n" + "If set to false, queries are sent one by one, waiting for the result before sending the next one. \n" @@ -278,116 +431,233 @@ public enum DefaultOptions { + " sending as many queries. Results will be read later, avoiding a lot of network latency when the client" + " and server aren't on the same host. \n" + "\n" - + "This option is mainly effective when the client is distant from the server.", false), - USE_BATCH_MULTI_SEND_NUMBER("useBatchMultiSendNumber", 100, 1, "1.5.0", + + "This option is mainly effective when the client is distant from the server.", + false), + USE_BATCH_MULTI_SEND_NUMBER( + "useBatchMultiSendNumber", + 100, + 1, + "1.5.0", "When option useBatchMultiSend is active," - + " indicate the maximum query send in a row before reading results.", false), - LOGGING("log", Boolean.FALSE, "1.5.0", "Enable log information. \n" - + "require Slf4j version > 1.4 dependency.\n" - + "Log level correspond to Slf4j logging implementation", false), + + " indicate the maximum query send in a row before reading results.", + false), + LOGGING( + "log", + Boolean.FALSE, + "1.5.0", + "Enable log information. \n" + + "require Slf4j version > 1.4 dependency.\n" + + "Log level correspond to Slf4j logging implementation", + false), PROFILE_SQL("profileSql", Boolean.FALSE, "1.5.0", "log query execution time.", false), MAX_QUERY_LOG_SIZE("maxQuerySizeToLog", 1024, 0, "1.5.0", "Max query log size.", false), - SLOW_QUERY_TIME("slowQueryThresholdNanos", null, 0L, "1.5.0", - "Will log query with execution time superior" - + " to this value (if defined )", false), - PASSWORD_CHARACTER_ENCODING("passwordCharacterEncoding", "1.5.9", - "Indicate password encoding charset. If not set," - + " driver use platform's default charset.", false), - PIPELINE_AUTH("usePipelineAuth", (Boolean) null, "1.6.0", "*Not compatible with aurora*\n" - + "During connection, different queries are executed. When option is active those queries are send using" - + " pipeline (all queries are send, then only all results are reads), permitting faster connection " - + "creation", false), - ENABLE_PACKET_DEBUG("enablePacketDebug", Boolean.FALSE, "1.6.0", + SLOW_QUERY_TIME( + "slowQueryThresholdNanos", + null, + 0L, + "1.5.0", + "Will log query with execution time superior" + " to this value (if defined )", + false), + PASSWORD_CHARACTER_ENCODING( + "passwordCharacterEncoding", + "1.5.9", + "Indicate password encoding charset. If not set," + " driver use platform's default charset.", + false), + PIPELINE_AUTH( + "usePipelineAuth", + (Boolean) null, + "1.6.0", + "*Not compatible with aurora*\n" + + "During connection, different queries are executed. When option is active those queries are send using" + + " pipeline (all queries are send, then only all results are reads), permitting faster connection " + + "creation", + false), + ENABLE_PACKET_DEBUG( + "enablePacketDebug", + Boolean.FALSE, + "1.6.0", "Driver will save the last 16 MariaDB packet " + "exchanges (limited to first 1000 bytes). Hexadecimal value of those packets will be added to stacktrace" + " when an IOException occur.\n" + "This option has no impact on performance but driver will then take 16kb more memory.", false), - SSL_HOSTNAME_VERIFICATION("disableSslHostnameVerification", Boolean.FALSE, "2.1.0", + SSL_HOSTNAME_VERIFICATION( + "disableSslHostnameVerification", + Boolean.FALSE, + "2.1.0", "When using ssl, the driver " + "checks the hostname against the server's identity as presented in the server's certificate (checking " + "alternative names or the certificate CN) to prevent man-in-the-middle attacks. This option permits " + "deactivating this validation. Hostname verification is disabled when the trustServerCertificate " - + "option is set", false), - USE_BULK_PROTOCOL("useBulkStmts", Boolean.FALSE, "2.1.0", + + "option is set", + false), + USE_BULK_PROTOCOL( + "useBulkStmts", + Boolean.FALSE, + "2.1.0", "Use dedicated COM_STMT_BULK_EXECUTE protocol for batch " + "insert when possible. (batch without Statement.RETURN_GENERATED_KEYS and streams) to have faster batch. " - + "(significant only if server MariaDB >= 10.2.7)", false), - AUTOCOMMIT("autocommit", Boolean.TRUE, "2.2.0", - "Set default autocommit value on connection initialization", false), - POOL("pool", Boolean.FALSE, "2.2.0", + + "(significant only if server MariaDB >= 10.2.7)", + false), + AUTOCOMMIT( + "autocommit", + Boolean.TRUE, + "2.2.0", + "Set default autocommit value on connection initialization", + false), + POOL( + "pool", + Boolean.FALSE, + "2.2.0", "Use pool. This option is useful only if not using a DataSource object, but " - + "only a connection object.", false), - POOL_NAME("poolName", "2.2.0", + + "only a connection object.", + false), + POOL_NAME( + "poolName", + "2.2.0", "Pool name that permits identifying threads. default: auto-generated as " - + "MariaDb-pool-", false), - MAX_POOL_SIZE("maxPoolSize", 8, 1, "2.2.0", - "The maximum number of physical connections that the pool should " - + "contain.", false), - MIN_POOL_SIZE("minPoolSize", (Integer) null, 0, "2.2.0", + + "MariaDb-pool-", + false), + MAX_POOL_SIZE( + "maxPoolSize", + 8, + 1, + "2.2.0", + "The maximum number of physical connections that the pool should " + "contain.", + false), + MIN_POOL_SIZE( + "minPoolSize", + (Integer) null, + 0, + "2.2.0", "When connections are removed due to not being used for " + "longer than than \"maxIdleTime\", connections are closed and removed from the pool. \"minPoolSize\" " + "indicates the number of physical connections the pool should keep available at all times. Should be less" - + " or equal to maxPoolSize.", false), - MAX_IDLE_TIME("maxIdleTime", 600, Options.MIN_VALUE__MAX_IDLE_TIME, "2.2.0", + + " or equal to maxPoolSize.", + false), + MAX_IDLE_TIME( + "maxIdleTime", + 600, + Options.MIN_VALUE__MAX_IDLE_TIME, + "2.2.0", "The maximum amount of time in seconds" + " that a connection can stay in the pool when not used. This value must always be below @wait_timeout" + " value - 45s \n" - + "Default: 600 in seconds (=10 minutes), minimum value is 60 seconds", false), - POOL_VALID_MIN_DELAY("poolValidMinDelay", 1000, 0, "2.2.0", + + "Default: 600 in seconds (=10 minutes), minimum value is 60 seconds", + false), + POOL_VALID_MIN_DELAY( + "poolValidMinDelay", + 1000, + 0, + "2.2.0", "When asking a connection to pool, the pool will " + "validate the connection state. \"poolValidMinDelay\" permits disabling this validation if the connection" + " has been borrowed recently avoiding useless verifications in case of frequent reuse of connections. " - + "0 means validation is done each time the connection is asked.", false), - STATIC_GLOBAL("staticGlobal", Boolean.FALSE, "2.2.0", + + "0 means validation is done each time the connection is asked.", + false), + STATIC_GLOBAL( + "staticGlobal", + Boolean.FALSE, + "2.2.0", "Indicates the values of the global variables " + "max_allowed_packet, wait_timeout, autocommit, auto_increment_increment, time_zone, system_time_zone and" + " tx_isolation) won't be changed, permitting the pool to create new connections faster.", false), - REGISTER_POOL_JMX("registerJmxPool", Boolean.TRUE, "2.2.0", "Register JMX monitoring pools.", - false), - USE_RESET_CONNECTION("useResetConnection", Boolean.FALSE, "2.2.0", + REGISTER_POOL_JMX( + "registerJmxPool", Boolean.TRUE, "2.2.0", "Register JMX monitoring pools.", false), + USE_RESET_CONNECTION( + "useResetConnection", + Boolean.FALSE, + "2.2.0", "When a connection is closed() " + "(given back to pool), the pool resets the connection state. Setting this option, the prepare command " + "will be deleted, session variables changed will be reset, and user variables will be destroyed when the" + " server permits it (>= MariaDB 10.2.4, >= MySQL 5.7.3), permitting saving memory on the server if the " + "application make extensive use of variables. Must not be used with the useServerPrepStmts option", false), - ALLOW_MASTER_DOWN("allowMasterDownConnection", Boolean.FALSE, "2.2.0", + ALLOW_MASTER_DOWN( + "allowMasterDownConnection", + Boolean.FALSE, + "2.2.0", "When using master/slave configuration, " + "permit to create connection when master is down. If no master is up, default connection is then a slave " - + "and Connection.isReadOnly() will then return true.", false), - GALERA_ALLOWED_STATE("galeraAllowedState", "2.2.5", + + "and Connection.isReadOnly() will then return true.", + false), + GALERA_ALLOWED_STATE( + "galeraAllowedState", + "2.2.5", "Usually, Connection.isValid just send an empty packet to " + "server, and server send a small response to ensure connectivity. When this option is set, connector will" + " ensure Galera server state \"wsrep_local_state\" correspond to allowed values (separated by comma). " - + "Example \"4,5\", recommended is \"4\". see galera state to know more.", false), - USE_AFFECTED_ROWS("useAffectedRows", Boolean.FALSE, "2.3.0", + + "Example \"4,5\", recommended is \"4\". see galera state to know more.", + false), + USE_AFFECTED_ROWS( + "useAffectedRows", + Boolean.FALSE, + "2.3.0", "If false (default), use \"found rows\" for the row " + "count of statements. This corresponds to the JDBC standard.\n" + "If true, use \"affected rows\" for the row count.\n" + "This changes the behavior of, for example, UPDATE... ON DUPLICATE KEY statements.", false), - INCLUDE_STATUS("includeInnodbStatusInDeadlockExceptions", Boolean.FALSE, "2.3.0", + INCLUDE_STATUS( + "includeInnodbStatusInDeadlockExceptions", + Boolean.FALSE, + "2.3.0", "add \"SHOW ENGINE INNODB STATUS\" result to exception trace when having a deadlock exception", false), - INCLUDE_THREAD_DUMP("includeThreadDumpInDeadlockExceptions", Boolean.FALSE, "2.3.0", - "add thread dump to exception trace when having a deadlock exception", false), - READ_AHEAD("useReadAheadInput", Boolean.TRUE, "2.4.0", - "use a buffered inputSteam that read socket available data", false), - KEY_STORE_TYPE("keyStoreType", (String) null, "2.4.0", - "indicate key store type (JKS/PKCS12). default is null, then using java default type", false), - TRUST_STORE_TYPE("trustStoreType", (String) null, "2.4.0", - "indicate trust store type (JKS/PKCS12). default is null, then using java default type", false), - SERVICE_PRINCIPAL_NAME("servicePrincipalName", (String) null, "2.4.0", + INCLUDE_THREAD_DUMP( + "includeThreadDumpInDeadlockExceptions", + Boolean.FALSE, + "2.3.0", + "add thread dump to exception trace when having a deadlock exception", + false), + READ_AHEAD( + "useReadAheadInput", + Boolean.TRUE, + "2.4.0", + "use a buffered inputSteam that read socket available data", + false), + KEY_STORE_TYPE( + "keyStoreType", + (String) null, + "2.4.0", + "indicate key store type (JKS/PKCS12). default is null, then using java default type", + false), + TRUST_STORE_TYPE( + "trustStoreType", + (String) null, + "2.4.0", + "indicate trust store type (JKS/PKCS12). default is null, then using java default type", + false), + SERVICE_PRINCIPAL_NAME( + "servicePrincipalName", + (String) null, + "2.4.0", "when using GSSAPI authentication, SPN (Service Principal Name) use the server SPN information. When set, " - + "connector will use this value, ignoring server information", false), - DEFAULT_FETCH_SIZE("defaultFetchSize", 0, 0, "2.4.2", - "The driver will call setFetchSize(n) with this value on all newly-created Statements", false), - USE_MYSQL_AS_DATABASE("useMysqlMetadata", Boolean.FALSE, "2.4.1", - "force DatabaseMetadata.getDatabaseProductName() " - + "to return \"MySQL\" as database, not real database type", false); - + + "connector will use this value, ignoring server information", + false), + DEFAULT_FETCH_SIZE( + "defaultFetchSize", + 0, + 0, + "2.4.2", + "The driver will call setFetchSize(n) with this value on all newly-created Statements", + false), + USE_MYSQL_AS_DATABASE( + "useMysqlMetadata", + Boolean.FALSE, + "2.4.1", + "force DatabaseMetadata.getDatabaseProductName() " + + "to return \"MySQL\" as database, not real database type", + false), + BLANK_TABLE_NAME_META( + "blankTableNameMeta", + Boolean.FALSE, + "2.4.3", + "Resultset metadata getTableName always return blank. " + + "This option is mainly for ORACLE db compatibility", + false); private final String optionName; private final String description; @@ -396,12 +666,13 @@ public enum DefaultOptions { private final Object defaultValue; private final Object minValue; private final Object maxValue; - private final String implementationVersion; - DefaultOptions(final String optionName, final String implementationVersion, String description, + DefaultOptions( + final String optionName, + final String implementationVersion, + String description, boolean required) { this.optionName = optionName; - this.implementationVersion = implementationVersion; this.description = description; this.required = required; objType = String.class; @@ -410,13 +681,13 @@ public enum DefaultOptions { maxValue = null; } - DefaultOptions(final String optionName, + DefaultOptions( + final String optionName, final String defaultValue, final String implementationVersion, String description, boolean required) { this.optionName = optionName; - this.implementationVersion = implementationVersion; this.description = description; this.required = required; objType = String.class; @@ -425,7 +696,8 @@ public enum DefaultOptions { maxValue = null; } - DefaultOptions(final String optionName, + DefaultOptions( + final String optionName, final Boolean defaultValue, final String implementationVersion, String description, @@ -433,14 +705,14 @@ public enum DefaultOptions { this.optionName = optionName; this.objType = Boolean.class; this.defaultValue = defaultValue; - this.implementationVersion = implementationVersion; this.description = description; this.required = required; minValue = null; maxValue = null; } - DefaultOptions(final String optionName, + DefaultOptions( + final String optionName, final Integer defaultValue, final Integer minValue, final String implementationVersion, @@ -451,12 +723,12 @@ public enum DefaultOptions { this.defaultValue = defaultValue; this.minValue = minValue; this.maxValue = Integer.MAX_VALUE; - this.implementationVersion = implementationVersion; this.description = description; this.required = required; } - DefaultOptions(final String optionName, + DefaultOptions( + final String optionName, final Long defaultValue, final Long minValue, final String implementationVersion, @@ -467,13 +739,12 @@ public enum DefaultOptions { this.defaultValue = defaultValue; this.minValue = minValue; this.maxValue = Long.MAX_VALUE; - this.implementationVersion = implementationVersion; this.description = description; this.required = required; } - - DefaultOptions(final String optionName, + DefaultOptions( + final String optionName, final Integer[] defaultValue, final Integer minValue, final String implementationVersion, @@ -484,7 +755,6 @@ public enum DefaultOptions { this.defaultValue = defaultValue; this.minValue = minValue; this.maxValue = Integer.MAX_VALUE; - this.implementationVersion = implementationVersion; this.description = description; this.required = required; } @@ -497,7 +767,7 @@ public static Options defaultValues(final HaMode haMode) { * Generate an Options object with default value corresponding to High Availability mode. * * @param haMode current high Availability mode - * @param pool is for pool + * @param pool is for pool * @return Options object initialized */ public static Options defaultValues(HaMode haMode, boolean pool) { @@ -511,9 +781,9 @@ public static Options defaultValues(HaMode haMode, boolean pool) { /** * Parse additional properties. * - * @param haMode current haMode. + * @param haMode current haMode. * @param urlParameters options defined in url - * @param options initial options + * @param options initial options */ public static void parse(final HaMode haMode, final String urlParameters, final Options options) { Properties prop = new Properties(); @@ -521,8 +791,8 @@ public static void parse(final HaMode haMode, final String urlParameters, final optionCoherenceValidation(options); } - private static Options parse(final HaMode haMode, final String urlParameters, - final Properties properties) { + private static Options parse( + final HaMode haMode, final String urlParameters, final Properties properties) { Options options = parse(haMode, urlParameters, properties, null); optionCoherenceValidation(options); return options; @@ -531,13 +801,14 @@ private static Options parse(final HaMode haMode, final String urlParameters, /** * Parse additional properties . * - * @param haMode current haMode. + * @param haMode current haMode. * @param urlParameters options defined in url - * @param properties options defined by properties - * @param options initial options + * @param properties options defined by properties + * @param options initial options * @return options */ - public static Options parse(final HaMode haMode, + public static Options parse( + final HaMode haMode, final String urlParameters, final Properties properties, final Options options) { @@ -553,20 +824,19 @@ public static Options parse(final HaMode haMode, if (!properties.containsKey(parameter.substring(0, pos))) { properties.setProperty(parameter.substring(0, pos), parameter.substring(pos + 1)); } - } } } return parse(haMode, properties, options); } - private static Options parse(final HaMode haMode, final Properties properties, - final Options paramOptions) { + private static Options parse( + final HaMode haMode, final Properties properties, final Options paramOptions) { final Options options = paramOptions != null ? paramOptions : new Options(); try { - //Option object is already initialized to default values. - //loop on properties, + // Option object is already initialized to default values. + // loop on properties, // - check DefaultOption to check that property value correspond to type (and range) // - set values for (final String key : properties.stringPropertyNames()) { @@ -590,8 +860,12 @@ private static Options parse(final HaMode haMode, final Properties properties, break; default: - throw new IllegalArgumentException("Optional parameter " + o.optionName - + " must be boolean (true/false or 0/1) was \"" + propertyValue + "\""); + throw new IllegalArgumentException( + "Optional parameter " + + o.optionName + + " must be boolean (true/false or 0/1) was \"" + + propertyValue + + "\""); } } else if (o.objType.equals(Integer.class)) { try { @@ -600,16 +874,26 @@ private static Options parse(final HaMode haMode, final Properties properties, assert o.maxValue != null; if (value.compareTo((Integer) o.minValue) < 0 || value.compareTo((Integer) o.maxValue) > 0) { - throw new IllegalArgumentException("Optional parameter " + o.optionName - + " must be greater or equal to " + o.minValue - + (((Integer) o.maxValue != Integer.MAX_VALUE) ? " and smaller than " - + o.maxValue : " ") - + ", was \"" + propertyValue + "\""); + throw new IllegalArgumentException( + "Optional parameter " + + o.optionName + + " must be greater or equal to " + + o.minValue + + (((Integer) o.maxValue != Integer.MAX_VALUE) + ? " and smaller than " + o.maxValue + : " ") + + ", was \"" + + propertyValue + + "\""); } field.set(options, value); } catch (NumberFormatException n) { - throw new IllegalArgumentException("Optional parameter " + o.optionName - + " must be Integer, was \"" + propertyValue + "\""); + throw new IllegalArgumentException( + "Optional parameter " + + o.optionName + + " must be Integer, was \"" + + propertyValue + + "\""); } } else if (o.objType.equals(Long.class)) { try { @@ -618,22 +902,32 @@ private static Options parse(final HaMode haMode, final Properties properties, assert o.maxValue != null; if (value.compareTo((Long) o.minValue) < 0 || value.compareTo((Long) o.maxValue) > 0) { - throw new IllegalArgumentException("Optional parameter " + o.optionName - + " must be greater or equal to " + o.minValue - + (((Long) o.maxValue != Long.MAX_VALUE) ? " and smaller than " + o.maxValue - : " ") - + ", was \"" + propertyValue + "\""); + throw new IllegalArgumentException( + "Optional parameter " + + o.optionName + + " must be greater or equal to " + + o.minValue + + (((Long) o.maxValue != Long.MAX_VALUE) + ? " and smaller than " + o.maxValue + : " ") + + ", was \"" + + propertyValue + + "\""); } field.set(options, value); } catch (NumberFormatException n) { - throw new IllegalArgumentException("Optional parameter " + o.optionName - + " must be Long, was \"" + propertyValue + "\""); + throw new IllegalArgumentException( + "Optional parameter " + + o.optionName + + " must be Long, was \"" + + propertyValue + + "\""); } } } } - //special case : field with multiple default according to HA_MODE + // special case : field with multiple default according to HA_MODE if (options.socketTimeout == null) { options.socketTimeout = ((Integer[]) SOCKET_TIMEOUT.defaultValue)[haMode.ordinal()]; } @@ -641,7 +935,7 @@ private static Options parse(final HaMode haMode, final Properties properties, } catch (NoSuchFieldException | IllegalAccessException n) { n.printStackTrace(); } catch (SecurityException s) { - //only for jws, so never thrown + // only for jws, so never thrown throw new IllegalArgumentException("Security too restrictive : " + s.getMessage()); } @@ -655,21 +949,23 @@ private static Options parse(final HaMode haMode, final Properties properties, */ public static void optionCoherenceValidation(final Options options) { - //disable use server prepare id using client rewrite + // disable use server prepare id using client rewrite if (options.rewriteBatchedStatements) { options.useServerPrepStmts = false; } - //pipe cannot use read and write socket simultaneously + // pipe cannot use read and write socket simultaneously if (options.pipe != null) { options.useBatchMultiSend = false; options.usePipelineAuth = false; } - //if min pool size default to maximum pool size if not set + // if min pool size default to maximum pool size if not set if (options.pool) { - options.minPoolSize = options.minPoolSize == null ? options.maxPoolSize - : Math.min(options.minPoolSize, options.maxPoolSize); + options.minPoolSize = + options.minPoolSize == null + ? options.maxPoolSize + : Math.min(options.minPoolSize, options.maxPoolSize); } // if fetchSize is set to less than 0, default it to 0 @@ -682,11 +978,11 @@ public static void optionCoherenceValidation(final Options options) { * Generate parameter String equivalent to options. * * @param options options - * @param haMode high availability Mode - * @param sb String builder + * @param haMode high availability Mode + * @param sb String builder */ - public static void propertyString(final Options options, final HaMode haMode, - final StringBuilder sb) { + public static void propertyString( + final Options options, final HaMode haMode, final StringBuilder sb) { try { boolean first = true; for (DefaultOptions o : DefaultOptions.values()) { @@ -699,8 +995,7 @@ public static void propertyString(final Options options, final HaMode haMode, } else { sb.append('&'); } - sb.append(o.optionName) - .append('='); + sb.append(o.optionName).append('='); if (o.objType.equals(String.class)) { sb.append((String) value); } else if (o.objType.equals(Boolean.class)) { diff --git a/src/main/java/org/mariadb/jdbc/internal/util/Options.java b/src/main/java/org/mariadb/jdbc/internal/util/Options.java index 2734bc55c..6099eaa4a 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/Options.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/Options.java @@ -18,53 +18,24 @@ * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to Monty Program Ab info@montyprogram.com. * - * This particular MariaDB Client for Java file is work - * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to - * the following copyright and notice provisions: - * - * Copyright (c) 2009-2011, Marcus Eriksson - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * Neither the name of the driver nor the names of its contributors may not be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * */ package org.mariadb.jdbc.internal.util; import java.lang.reflect.Field; import java.sql.DriverManager; +import java.util.Objects; @SuppressWarnings("ConstantConditions") public class Options implements Cloneable { public static final int MIN_VALUE__MAX_IDLE_TIME = 60; - //standard options + // standard options public String user; public String password; - //divers + // divers public boolean trustServerCertificate; public String serverSslCert; public String trustStore; @@ -95,6 +66,7 @@ public class Options implements Cloneable { public boolean useCompression; public boolean interactiveClient; public String passwordCharacterEncoding; + public boolean blankTableNameMeta; public boolean useSsl; public String enabledSslCipherSuites; @@ -132,13 +104,13 @@ public class Options implements Cloneable { public String servicePrincipalName; public int defaultFetchSize; - //logging options + // logging options public boolean log; public boolean profileSql; public int maxQuerySizeToLog = 1024; public Long slowQueryThresholdNanos; - //HA options + // HA options public boolean assureReadOnly; public boolean autoReconnect; public boolean failOnReadOnly; @@ -149,7 +121,7 @@ public class Options implements Cloneable { public boolean allowMasterDownConnection; public String galeraAllowedState; - //Pool options + // Pool options public boolean pool; public String poolName; public int maxPoolSize = 8; @@ -175,10 +147,10 @@ public String toString() { try { result.append(field.getName()); result.append(": "); - //requires access to private field: + // requires access to private field: result.append(field.get(this)); } catch (IllegalAccessException ex) { - //ignore error + // ignore error } result.append(newLine); } @@ -216,6 +188,9 @@ public boolean equals(Object obj) { if (tcpAbortiveClose != opt.tcpAbortiveClose) { return false; } + if (blankTableNameMeta != opt.blankTableNameMeta) { + return false; + } if (allowMultiQueries != opt.allowMultiQueries) { return false; } @@ -351,31 +326,28 @@ public boolean equals(Object obj) { if (poolValidMinDelay != opt.poolValidMinDelay) { return false; } - if (user != null ? !user.equals(opt.user) : opt.user != null) { + if (!Objects.equals(user, opt.user)) { return false; } - if (password != null ? !password.equals(opt.password) : opt.password != null) { + if (!Objects.equals(password, opt.password)) { return false; } - if (serverSslCert != null ? !serverSslCert.equals(opt.serverSslCert) - : opt.serverSslCert != null) { + if (!Objects.equals(serverSslCert, opt.serverSslCert)) { return false; } - if (trustStore != null ? !trustStore.equals(opt.trustStore) : opt.trustStore != null) { + if (!Objects.equals(trustStore, opt.trustStore)) { return false; } - if (trustStorePassword != null ? !trustStorePassword.equals(opt.trustStorePassword) - : opt.trustStorePassword != null) { + if (!Objects.equals(trustStorePassword, opt.trustStorePassword)) { return false; } - if (keyStore != null ? !keyStore.equals(opt.keyStore) : opt.keyStore != null) { + if (!Objects.equals(keyStore, opt.keyStore)) { return false; } - if (keyStorePassword != null ? !keyStorePassword.equals(opt.keyStorePassword) - : opt.keyStorePassword != null) { + if (!Objects.equals(keyStorePassword, opt.keyStorePassword)) { return false; } - if (keyPassword != null ? !keyPassword.equals(opt.keyPassword) : opt.keyPassword != null) { + if (!Objects.equals(keyPassword, opt.keyPassword)) { return false; } if (enabledSslProtocolSuites != null) { @@ -385,34 +357,31 @@ public boolean equals(Object obj) { } else if (opt.enabledSslProtocolSuites != null) { return false; } - if (socketFactory != null ? !socketFactory.equals(opt.socketFactory) - : opt.socketFactory != null) { + if (!Objects.equals(socketFactory, opt.socketFactory)) { return false; } if (connectTimeout != opt.connectTimeout) { return false; } - if (pipe != null ? !pipe.equals(opt.pipe) : opt.pipe != null) { + if (!Objects.equals(pipe, opt.pipe)) { return false; } - if (localSocket != null ? !localSocket.equals(opt.localSocket) : opt.localSocket != null) { + if (!Objects.equals(localSocket, opt.localSocket)) { return false; } - if (sharedMemory != null ? !sharedMemory.equals(opt.sharedMemory) : opt.sharedMemory != null) { + if (!Objects.equals(sharedMemory, opt.sharedMemory)) { return false; } - if (tcpRcvBuf != null ? !tcpRcvBuf.equals(opt.tcpRcvBuf) : opt.tcpRcvBuf != null) { + if (!Objects.equals(tcpRcvBuf, opt.tcpRcvBuf)) { return false; } - if (tcpSndBuf != null ? !tcpSndBuf.equals(opt.tcpSndBuf) : opt.tcpSndBuf != null) { + if (!Objects.equals(tcpSndBuf, opt.tcpSndBuf)) { return false; } - if (localSocketAddress != null ? !localSocketAddress.equals(opt.localSocketAddress) - : opt.localSocketAddress != null) { + if (!Objects.equals(localSocketAddress, opt.localSocketAddress)) { return false; } - if (socketTimeout != null ? !socketTimeout.equals(opt.socketTimeout) - : opt.socketTimeout != null) { + if (!Objects.equals(socketTimeout, opt.socketTimeout)) { return false; } if (passwordCharacterEncoding != null) { @@ -423,16 +392,13 @@ public boolean equals(Object obj) { return false; } - if (enabledSslCipherSuites != null ? !enabledSslCipherSuites.equals(opt.enabledSslCipherSuites) - : opt.enabledSslCipherSuites != null) { + if (!Objects.equals(enabledSslCipherSuites, opt.enabledSslCipherSuites)) { return false; } - if (sessionVariables != null ? !sessionVariables.equals(opt.sessionVariables) - : opt.sessionVariables != null) { + if (!Objects.equals(sessionVariables, opt.sessionVariables)) { return false; } - if (serverTimezone != null ? !serverTimezone.equals(opt.serverTimezone) - : opt.serverTimezone != null) { + if (!Objects.equals(serverTimezone, opt.serverTimezone)) { return false; } if (prepStmtCacheSize != opt.prepStmtCacheSize) { @@ -444,36 +410,31 @@ public boolean equals(Object obj) { if (callableStmtCacheSize != opt.callableStmtCacheSize) { return false; } - if (connectionAttributes != null ? !connectionAttributes.equals(opt.connectionAttributes) - : opt.connectionAttributes != null) { + if (!Objects.equals(connectionAttributes, opt.connectionAttributes)) { return false; } - if (useBatchMultiSend != null ? !useBatchMultiSend.equals(opt.useBatchMultiSend) - : opt.useBatchMultiSend != null) { + if (!Objects.equals(useBatchMultiSend, opt.useBatchMultiSend)) { return false; } - if (usePipelineAuth != null ? !usePipelineAuth.equals(opt.usePipelineAuth) - : opt.usePipelineAuth != null) { + if (!Objects.equals(usePipelineAuth, opt.usePipelineAuth)) { return false; } if (maxQuerySizeToLog != opt.maxQuerySizeToLog) { return false; } - if (slowQueryThresholdNanos != null ? !slowQueryThresholdNanos - .equals(opt.slowQueryThresholdNanos) : opt.slowQueryThresholdNanos != null) { + if (!Objects.equals(slowQueryThresholdNanos, opt.slowQueryThresholdNanos)) { return false; } if (autocommit != opt.autocommit) { return false; } - if (poolName != null ? !poolName.equals(opt.poolName) : opt.poolName != null) { + if (!Objects.equals(poolName, opt.poolName)) { return false; } - if (galeraAllowedState != null ? !galeraAllowedState.equals(opt.galeraAllowedState) - : opt.galeraAllowedState != null) { + if (!Objects.equals(galeraAllowedState, opt.galeraAllowedState)) { return false; } - return minPoolSize != null ? minPoolSize.equals(opt.minPoolSize) : opt.minPoolSize == null; + return Objects.equals(minPoolSize, opt.minPoolSize); } @SuppressWarnings("SimplifiableIfStatement") @@ -508,8 +469,9 @@ public int hashCode() { result = 31 * result + (rewriteBatchedStatements ? 1 : 0); result = 31 * result + (useCompression ? 1 : 0); result = 31 * result + (interactiveClient ? 1 : 0); - result = 31 * result + (passwordCharacterEncoding != null ? passwordCharacterEncoding.hashCode() - : 0); + result = + 31 * result + + (passwordCharacterEncoding != null ? passwordCharacterEncoding.hashCode() : 0); result = 31 * result + (useSsl ? 1 : 0); result = 31 * result + (enabledSslCipherSuites != null ? enabledSslCipherSuites.hashCode() : 0); result = 31 * result + (sessionVariables != null ? sessionVariables.hashCode() : 0); diff --git a/src/test/java/org/mariadb/jdbc/ResultSetMetaDataTest.java b/src/test/java/org/mariadb/jdbc/ResultSetMetaDataTest.java index 613f45e10..0a274bfd8 100644 --- a/src/test/java/org/mariadb/jdbc/ResultSetMetaDataTest.java +++ b/src/test/java/org/mariadb/jdbc/ResultSetMetaDataTest.java @@ -18,36 +18,6 @@ * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to Monty Program Ab info@montyprogram.com. * - * This particular MariaDB Client for Java file is work - * derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to - * the following copyright and notice provisions: - * - * Copyright (c) 2009-2011, Marcus Eriksson - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this - * list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * Neither the name of the driver nor the names of its contributors may not be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * */ package org.mariadb.jdbc; @@ -224,17 +194,36 @@ public void tableNameTest() throws Exception { // add useOldAliasMetadataBehavior to get the alias instead of the real // table name - try (Connection connection = setConnection("&useOldAliasMetadataBehavior=true")) { + try (Connection connection = setConnection("&useOldAliasMetadataBehavior")) { rs = connection.createStatement().executeQuery( "SELECT id AS id_alias FROM t3 AS t1_alias"); rsmd = rs.getMetaData(); - // this should return the alias name of the table, i.e. old behavior logInfo(rsmd.getTableName(1)); assertEquals(rsmd.getTableName(1), "t1_alias"); assertEquals(rsmd.getColumnLabel(1), "id_alias"); assertEquals(rsmd.getColumnName(1), "id_alias"); } + + try (Connection connection = setConnection("&blankTableNameMeta")) { + rs = connection.createStatement().executeQuery( + "SELECT id AS id_alias FROM t3 AS t1_alias"); + rsmd = rs.getMetaData(); + + assertEquals(rsmd.getTableName(1), ""); + assertEquals(rsmd.getColumnLabel(1), "id_alias"); + assertEquals(rsmd.getColumnName(1), "id"); + } + + try (Connection connection = setConnection("&blankTableNameMeta&useOldAliasMetadataBehavior")) { + rs = connection.createStatement().executeQuery( + "SELECT id AS id_alias FROM t3 AS t1_alias"); + rsmd = rs.getMetaData(); + + assertEquals(rsmd.getTableName(1), ""); + assertEquals(rsmd.getColumnLabel(1), "id_alias"); + assertEquals(rsmd.getColumnName(1), "id_alias"); + } } } From 5cdf78545344ffc8a7876d3540a6ca89f9dc114b Mon Sep 17 00:00:00 2001 From: rusher Date: Tue, 30 Jul 2019 16:51:00 +0200 Subject: [PATCH 13/19] [misc] code style correction --- .../mariadb/jdbc/BasePrepareStatement.java | 1029 +++--- .../mariadb/jdbc/MariaDbDatabaseMetaData.java | 3141 ++++++++++------- .../jdbc/ServerSidePreparedStatement.java | 2 +- .../com/send/parameters/BooleanParameter.java | 3 +- .../com/send/parameters/ByteParameter.java | 6 + .../send/parameters/LocalTimeParameter.java | 25 +- .../jdbc/internal/util/DefaultOptions.java | 2 +- .../mariadb/jdbc/internal/util/Options.java | 2 +- .../org/mariadb/jdbc/internal/util/Utils.java | 279 +- .../java/org/mariadb/jdbc/LocalTimeTest.java | 348 +- .../mariadb/jdbc/ResultSetMetaDataTest.java | 2 +- .../org/mariadb/jdbc/ScalarFunctionsTest.java | 27 +- 12 files changed, 2767 insertions(+), 2099 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java index b168118a9..322f21b73 100644 --- a/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java +++ b/src/main/java/org/mariadb/jdbc/BasePrepareStatement.java @@ -84,7 +84,6 @@ import java.util.Calendar; import java.util.TimeZone; import org.mariadb.jdbc.internal.ColumnType; -import org.mariadb.jdbc.internal.com.send.parameters.LocalTimeParameter; import org.mariadb.jdbc.internal.com.send.parameters.BigDecimalParameter; import org.mariadb.jdbc.internal.com.send.parameters.BooleanParameter; import org.mariadb.jdbc.internal.com.send.parameters.ByteArrayParameter; @@ -93,6 +92,7 @@ import org.mariadb.jdbc.internal.com.send.parameters.DoubleParameter; import org.mariadb.jdbc.internal.com.send.parameters.FloatParameter; import org.mariadb.jdbc.internal.com.send.parameters.IntParameter; +import org.mariadb.jdbc.internal.com.send.parameters.LocalTimeParameter; import org.mariadb.jdbc.internal.com.send.parameters.LongParameter; import org.mariadb.jdbc.internal.com.send.parameters.NullParameter; import org.mariadb.jdbc.internal.com.send.parameters.OffsetTimeParameter; @@ -113,26 +113,28 @@ public abstract class BasePrepareStatement extends MariaDbStatement implements P * The ISO-like date-time formatter that formats or parses a date-time with offset and zone, such * as '2011-12-03T10:15:30+01:00[Europe/Paris]'. and without the 'T' time delimiter * - *

This returns an immutable formatter capable of formatting and parsing - * a format that extends the ISO-8601 extended offset date-time format to add the time-zone.

- **/ - public static final DateTimeFormatter SPEC_ISO_ZONED_DATE_TIME = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .append(DateTimeFormatter.ISO_LOCAL_DATE) - .optionalStart() - .appendLiteral('T') - .optionalEnd() - .optionalStart() - .appendLiteral(' ') - .optionalEnd() - .append(DateTimeFormatter.ISO_LOCAL_TIME) - .appendOffsetId() - .optionalStart() - .appendLiteral('[') - .parseCaseSensitive() - .appendZoneRegionId() - .appendLiteral(']') - .toFormatter(); + *

This returns an immutable formatter capable of formatting and parsing a format that extends + * the ISO-8601 extended offset date-time format to add the time-zone. + */ + public static final DateTimeFormatter SPEC_ISO_ZONED_DATE_TIME = + new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(DateTimeFormatter.ISO_LOCAL_DATE) + .optionalStart() + .appendLiteral('T') + .optionalEnd() + .optionalStart() + .appendLiteral(' ') + .optionalEnd() + .append(DateTimeFormatter.ISO_LOCAL_TIME) + .appendOffsetId() + .optionalStart() + .appendLiteral('[') + .parseCaseSensitive() + .appendZoneRegionId() + .appendLiteral(']') + .toFormatter(); + protected int autoGeneratedKeys; protected boolean hasLongData = false; private boolean useFractionalSeconds; @@ -141,21 +143,20 @@ public abstract class BasePrepareStatement extends MariaDbStatement implements P /** * Constructor. Base class that permit setting parameters for client and server PrepareStatement. * - * @param connection current connection - * @param resultSetScrollType one of the following ResultSet constants: - * ResultSet.TYPE_FORWARD_ONLY, - * ResultSet.TYPE_SCROLL_INSENSITIVE, or - * ResultSet.TYPE_SCROLL_SENSITIVE - * @param resultSetConcurrency one of the following ResultSet constants: - * ResultSet.CONCUR_READ_ONLY or - * ResultSet.CONCUR_UPDATABLE - * @param autoGeneratedKeys a flag indicating whether auto-generated keys should be returned; - * one of - * Statement.RETURN_GENERATED_KEYS - * or Statement.NO_GENERATED_KEYS + * @param connection current connection + * @param resultSetScrollType one of the following ResultSet constants: + * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, or + * ResultSet.TYPE_SCROLL_SENSITIVE + * @param resultSetConcurrency one of the following ResultSet constants: + * ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE + * @param autoGeneratedKeys a flag indicating whether auto-generated keys should be returned; one + * of Statement.RETURN_GENERATED_KEYS or Statement.NO_GENERATED_KEYS */ - public BasePrepareStatement(MariaDbConnection connection, int resultSetScrollType, - int resultSetConcurrency, int autoGeneratedKeys) { + public BasePrepareStatement( + MariaDbConnection connection, + int resultSetScrollType, + int resultSetConcurrency, + int autoGeneratedKeys) { super(connection, resultSetScrollType, resultSetConcurrency); this.noBackslashEscapes = protocol.noBackslashEscapes(); this.useFractionalSeconds = options.useFractionalSeconds; @@ -184,27 +185,24 @@ public long executeLargeUpdate() throws SQLException { return getLargeUpdateCount(); } - protected abstract boolean executeInternal(int fetchSize) throws SQLException; /** * Sets the designated parameter to the given Reader object, which is the given - * number of characters long. When a very large UNICODE value is input to a - * LONGVARCHAR parameter, it may be more practical to send it via a - * java.io.Reader object. The data will be read from the stream as needed until - * end-of-file is reached. The JDBC driver will do any necessary conversion from UNICODE to the - * database char format. + * number of characters long. When a very large UNICODE value is input to a LONGVARCHAR + * parameter, it may be more practical to send it via a java.io.Reader + * object. The data will be read from the stream as needed until end-of-file is reached. The JDBC + * driver will do any necessary conversion from UNICODE to the database char format. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param reader the java.io.Reader object that contains the Unicode data - * @param length the number of characters in the stream + * @param reader the java.io.Reader object that contains the Unicode data + * @param length the number of characters in the stream * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setCharacterStream(final int parameterIndex, final Reader reader, final int length) throws SQLException { @@ -218,22 +216,20 @@ public void setCharacterStream(final int parameterIndex, final Reader reader, fi /** * Sets the designated parameter to the given Reader object, which is the given - * number of characters long. When a very large UNICODE value is input to a - * LONGVARCHAR parameter, it may be more practical to send it via a - * java.io.Reader object. The data will be read from the stream as needed until - * end-of-file is reached. The JDBC driver will do any necessary conversion from UNICODE to the - * database char format. + * number of characters long. When a very large UNICODE value is input to a LONGVARCHAR + * parameter, it may be more practical to send it via a java.io.Reader + * object. The data will be read from the stream as needed until end-of-file is reached. The JDBC + * driver will do any necessary conversion from UNICODE to the database char format. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param reader the java.io.Reader object that contains the Unicode data - * @param length the number of characters in the stream + * @param reader the java.io.Reader object that contains the Unicode data + * @param length the number of characters in the stream * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setCharacterStream(final int parameterIndex, final Reader reader, final long length) throws SQLException { @@ -245,27 +241,24 @@ public void setCharacterStream(final int parameterIndex, final Reader reader, fi hasLongData = true; } - /** * Sets the designated parameter to the given Reader object. When a very large * UNICODE value is input to a LONGVARCHAR parameter, it may be more practical to * send it via a java.io.Reader object. The data will be read from the stream as - * needed until end-of-file is reached. The JDBC driver will do any necessary conversion from + * needed until end-of-file is reached. The JDBC driver will do any necessary conversion from * UNICODE to the database char format. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * - *

Note: Consult your JDBC driver - * documentation to determine if it might be more efficient to use a version of - * setCharacterStream which takes a length parameter. + *

Note: Consult your JDBC driver documentation to determine if it might be more + * efficient to use a version of setCharacterStream which takes a length parameter. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param reader the java.io.Reader object that contains the Unicode data - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param reader the java.io.Reader object that contains the Unicode data + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setCharacterStream(final int parameterIndex, final Reader reader) throws SQLException { @@ -282,11 +275,10 @@ public void setCharacterStream(final int parameterIndex, final Reader reader) * driver converts this to an SQL REF value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param ref an SQL REF value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param ref an SQL REF value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setRef(final int parameterIndex, final Ref ref) throws SQLException { throw ExceptionMapper.getFeatureNotSupportedException("REF not supported"); @@ -294,47 +286,42 @@ public void setRef(final int parameterIndex, final Ref ref) throws SQLException /** * Sets the designated parameter to the given java.sql.Blob object. The driver - * converts this to an SQL - * BLOB value when it sends it to the database. + * converts this to an SQL BLOB value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param blob a Blob object that maps an SQL BLOB value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param blob a Blob object that maps an SQL BLOB value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setBlob(final int parameterIndex, final Blob blob) throws SQLException { if (blob == null) { setNull(parameterIndex, Types.BLOB); return; } - setParameter(parameterIndex, + setParameter( + parameterIndex, new StreamParameter(blob.getBinaryStream(), blob.length(), noBackslashEscapes)); hasLongData = true; } /** - * Sets the designated parameter to a InputStream object. The inputstream must - * contain the number of characters specified by length otherwise a SQLException - * will be generated when the - * PreparedStatement is executed. This method differs from the setBinaryStream + * Sets the designated parameter to a InputStream object. The inputstream must + * contain the number of characters specified by length otherwise a SQLException will + * be generated when the PreparedStatement is executed. This method differs from the + * setBinaryStream * (int, InputStream, int) method because it informs the driver that the parameter value - * should be sent to the server as a - * BLOB. When the setBinaryStream method is used, the driver may have - * to do extra work to determine whether the parameter data should be sent to the server as a - * LONGVARBINARY or a - * BLOB + * should be sent to the server as a BLOB. When the setBinaryStream + * method is used, the driver may have to do extra work to determine whether the parameter data + * should be sent to the server as a LONGVARBINARY or a BLOB * * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param inputStream An object that contains the data to set the parameter value to. - * @param length the number of bytes in the parameter data. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs; this method is called on a closed - * PreparedStatement; if the length - * specified is less than zero or if the number of bytes - * in the inputstream does not match the specfied length. + * @param inputStream An object that contains the data to set the parameter value to. + * @param length the number of bytes in the parameter data. + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs; this method is called on a closed + * PreparedStatement; if the length specified is less than zero or if the number of + * bytes in the inputstream does not match the specfied length. */ public void setBlob(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException { @@ -348,24 +335,21 @@ public void setBlob(final int parameterIndex, final InputStream inputStream, fin /** * Sets the designated parameter to a InputStream object. This method differs from - * the - * setBinaryStream (int, InputStream) method because it informs the driver that the - * parameter value should be sent to the server as a BLOB. When the - * setBinaryStream method is used, the driver may have to do extra work to determine - * whether the parameter data should be sent to the server as a - * LONGVARBINARY or a BLOB + * the setBinaryStream (int, InputStream) method because it informs the driver that + * the parameter value should be sent to the server as a BLOB. When the + * setBinaryStream method is used, the driver may have to do extra work to determine + * whether the parameter data should be sent to the server as a LONGVARBINARY or a + * BLOB * - *

Note: Consult your JDBC driver documentation to determine if it might be more - * efficient to use a version of setBlob which takes a length parameter.

+ *

Note: Consult your JDBC driver documentation to determine if it might be more + * efficient to use a version of setBlob which takes a length parameter. * * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param inputStream An object that contains the data to set the parameter value to. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs; this method is called on a closed - * PreparedStatement or if parameterIndex - * does not correspond to a parameter marker in the SQL - * statement, + * @param inputStream An object that contains the data to set the parameter value to. + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs; this method is called on a closed + * PreparedStatement or if parameterIndex does not correspond to a parameter marker in + * the SQL statement, */ public void setBlob(final int parameterIndex, final InputStream inputStream) throws SQLException { if (inputStream == null) { @@ -379,15 +363,13 @@ public void setBlob(final int parameterIndex, final InputStream inputStream) thr /** * Sets the designated parameter to the given java.sql.Clob object. The driver - * converts this to an SQL - * CLOB value when it sends it to the database. + * converts this to an SQL CLOB value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param clob a Clob object that maps an SQL CLOB value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param clob a Clob object that maps an SQL CLOB value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setClob(final int parameterIndex, final Clob clob) throws SQLException { if (clob == null) { @@ -395,33 +377,28 @@ public void setClob(final int parameterIndex, final Clob clob) throws SQLExcepti return; } - setParameter(parameterIndex, + setParameter( + parameterIndex, new ReaderParameter(clob.getCharacterStream(), clob.length(), noBackslashEscapes)); hasLongData = true; } /** - * Sets the designated parameter to a Reader object. The reader must contain the + * Sets the designated parameter to a Reader object. The reader must contain the * number of characters specified by length otherwise a SQLException will be - * generated when the - * PreparedStatement is executed. This method differs from the + * generated when the PreparedStatement is executed. This method differs from the * setCharacterStream (int, Reader, * int) method because it informs the driver that the parameter value should be sent to the - * server as a - * CLOB. When the setCharacterStream method is used, the driver may - * have to do extra work to determine whether the parameter data should be sent to the server as - * a - * LONGVARCHAR or a - * CLOB + * server as a CLOB. When the setCharacterStream method is used, the + * driver may have to do extra work to determine whether the parameter data should be sent to the + * server as a LONGVARCHAR or a CLOB * * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param reader An object that contains the data to set the parameter value to. - * @param length the number of characters in the parameter data. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs; this method is called on a closed - * PreparedStatement or if the length - * specified is less than zero. + * @param reader An object that contains the data to set the parameter value to. + * @param length the number of characters in the parameter data. + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs; this method is called on a closed + * PreparedStatement or if the length specified is less than zero. */ public void setClob(final int parameterIndex, final Reader reader, final long length) throws SQLException { @@ -431,63 +408,53 @@ public void setClob(final int parameterIndex, final Reader reader, final long le /** * Sets the designated parameter to a Reader object. This method differs from the * setCharacterStream (int, Reader) method because it informs the driver that the - * parameter value should be sent to the server as a CLOB. When the - * setCharacterStream method is used, the driver may have to do extra work to - * determine whether the parameter data should be sent to the server as a - * LONGVARCHAR or a CLOB + * parameter value should be sent to the server as a CLOB. When the + * setCharacterStream method is used, the driver may have to do extra work to determine + * whether the parameter data should be sent to the server as a LONGVARCHAR or a + * CLOB * - *

Note: Consult your JDBC driver documentation to determine if it might be more - * efficient to use a version of setClob which takes a length parameter.

+ *

Note: Consult your JDBC driver documentation to determine if it might be more + * efficient to use a version of setClob which takes a length parameter. * * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param reader An object that contains the data to set the parameter value to. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs; this method is called on a closed - * PreparedStatementor if parameterIndex - * does not correspond to a parameter marker in the SQL - * statement + * @param reader An object that contains the data to set the parameter value to. + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs; this method is called on a closed + * PreparedStatementor if parameterIndex does not correspond to a parameter marker in + * the SQL statement */ public void setClob(final int parameterIndex, final Reader reader) throws SQLException { setCharacterStream(parameterIndex, reader); } - /** * Sets the designated parameter to the given java.sql.Array object. The driver - * converts this to an SQL - * ARRAY value when it sends it to the database. + * converts this to an SQL ARRAY value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param array an Array object that maps an SQL ARRAY value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param array an Array object that maps an SQL ARRAY value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setArray(final int parameterIndex, final Array array) throws SQLException { throw ExceptionMapper.getFeatureNotSupportedException("Arrays not supported"); } - /** * Sets the designated parameter to the given java.sql.Date value, using the given - * Calendar object. The driver uses the Calendar object to construct - * an SQL - * DATE value, which the driver then sends to the database. With a - * Calendar object, the - * driver can calculate the date taking into account a custom timezone. If no + * Calendar object. The driver uses the Calendar object to construct an + * SQL DATE value, which the driver then sends to the database. With a Calendar + * object, the driver can calculate the date taking into account a custom timezone. If no * Calendar object is specified, the driver uses the default timezone, which is that * of the virtual machine running the application. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param date the parameter value - * @param cal the Calendar object the driver will use to construct the - * date + * @param date the parameter value + * @param cal the Calendar object the driver will use to construct the date * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setDate(final int parameterIndex, final Date date, final Calendar cal) throws SQLException { @@ -495,9 +462,10 @@ public void setDate(final int parameterIndex, final Date date, final Calendar ca setNull(parameterIndex, Types.DATE); return; } - setParameter(parameterIndex, - new DateParameter(date, cal != null ? cal.getTimeZone() : TimeZone.getDefault(), - protocol.getOptions())); + setParameter( + parameterIndex, + new DateParameter( + date, cal != null ? cal.getTimeZone() : TimeZone.getDefault(), protocol.getOptions())); } /** @@ -506,39 +474,34 @@ public void setDate(final int parameterIndex, final Date date, final Calendar ca * an SQL DATE value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param date the parameter value + * @param date the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setDate(int parameterIndex, Date date) throws SQLException { if (date == null) { setNull(parameterIndex, Types.DATE); return; } - setParameter(parameterIndex, - new DateParameter(date, TimeZone.getDefault(), protocol.getOptions())); + setParameter( + parameterIndex, new DateParameter(date, TimeZone.getDefault(), protocol.getOptions())); } /** * Sets the designated parameter to the given java.sql.Time value, using the given - * Calendar object. The driver uses the Calendar object to construct - * an SQL - * TIME value, which the driver then sends to the database. With a - * Calendar object, the - * driver can calculate the time taking into account a custom timezone. If no + * Calendar object. The driver uses the Calendar object to construct an + * SQL TIME value, which the driver then sends to the database. With a Calendar + * object, the driver can calculate the time taking into account a custom timezone. If no * Calendar object is specified, the driver uses the default timezone, which is that * of the virtual machine running the application. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param time the parameter value - * @param cal the Calendar object the driver will use to construct the - * time + * @param time the parameter value + * @param cal the Calendar object the driver will use to construct the time * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setTime(final int parameterIndex, final Time time, final Calendar cal) throws SQLException { @@ -546,51 +509,45 @@ public void setTime(final int parameterIndex, final Time time, final Calendar ca setNull(parameterIndex, ColumnType.TIME); return; } - setParameter(parameterIndex, - new TimeParameter(time, cal != null ? cal.getTimeZone() : TimeZone.getDefault(), - useFractionalSeconds)); + setParameter( + parameterIndex, + new TimeParameter( + time, cal != null ? cal.getTimeZone() : TimeZone.getDefault(), useFractionalSeconds)); } - /** * Sets the designated parameter to the given java.sql.Time value. the driver uses * the default timezone, which is that of the virtual machine running the application. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param time the parameter value + * @param time the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setTime(final int parameterIndex, final Time time) throws SQLException { if (time == null) { setNull(parameterIndex, ColumnType.TIME); return; } - setParameter(parameterIndex, - new TimeParameter(time, TimeZone.getDefault(), useFractionalSeconds)); + setParameter( + parameterIndex, new TimeParameter(time, TimeZone.getDefault(), useFractionalSeconds)); } /** * Sets the designated parameter to the given java.sql.Timestamp value, using the - * given - * Calendar object. The driver uses the Calendar object to construct - * an SQL - * TIMESTAMP value, which the driver then sends to the database. With a - * Calendar object, - * the driver can calculate the timestamp taking into account a custom timezone. If no - * Calendar object is specified, the driver uses the default timezone, which is that - * of the virtual machine running the application. + * given Calendar object. The driver uses the Calendar object to + * construct an SQL TIMESTAMP value, which the driver then sends to the database. + * With a Calendar object, the driver can calculate the timestamp taking into account + * a custom timezone. If no Calendar object is specified, the driver uses the default + * timezone, which is that of the virtual machine running the application. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param timestamp the parameter value - * @param cal the Calendar object the driver will use to construct the - * timestamp + * @param timestamp the parameter value + * @param cal the Calendar object the driver will use to construct the timestamp * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setTimestamp(final int parameterIndex, final Timestamp timestamp, final Calendar cal) throws SQLException { @@ -602,17 +559,15 @@ public void setTimestamp(final int parameterIndex, final Timestamp timestamp, fi setParameter(parameterIndex, new TimestampParameter(timestamp, tz, useFractionalSeconds)); } - /** * Sets the designated parameter to the given java.sql.Timestamp value. The driver * converts this to an SQL TIMESTAMP value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param timestamp the parameter value + * @param timestamp the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setTimestamp(final int parameterIndex, final Timestamp timestamp) throws SQLException { @@ -620,22 +575,21 @@ public void setTimestamp(final int parameterIndex, final Timestamp timestamp) setNull(parameterIndex, ColumnType.DATETIME); return; } - setParameter(parameterIndex, + setParameter( + parameterIndex, new TimestampParameter(timestamp, protocol.getTimeZone(), useFractionalSeconds)); - } /** * Sets the designated parameter to SQL NULL. * - *

Note: You must specify the parameter's SQL type.

+ *

Note: You must specify the parameter's SQL type. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param sqlType the SQL type code defined in java.sql.Types - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param sqlType the SQL type code defined in java.sql.Types + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setNull(final int parameterIndex, final int sqlType) throws SQLException { setParameter(parameterIndex, new NullParameter()); @@ -644,43 +598,40 @@ public void setNull(final int parameterIndex, final int sqlType) throws SQLExcep /** * Sets the designated parameter to SQL NULL. * - *

Note: You must specify the parameter's SQL type.

+ *

Note: You must specify the parameter's SQL type. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param mariadbType the type code defined in ColumnType - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param mariadbType the type code defined in ColumnType + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setNull(final int parameterIndex, final ColumnType mariadbType) throws SQLException { setParameter(parameterIndex, new NullParameter(mariadbType)); } /** - * Sets the designated parameter to SQL NULL. This version of the method - * setNull should be used for user-defined types and REF type parameters. Examples - * of user-defined types include: STRUCT, DISTINCT, JAVA_OBJECT, and named array types. + * Sets the designated parameter to SQL NULL. This version of the method + * setNull should be used for user-defined types and REF type parameters. Examples of + * user-defined types include: STRUCT, DISTINCT, JAVA_OBJECT, and named array types. * - *

Note: To be portable, applications must give the SQL type code and the - * fully-qualified SQL type name when specifying a NULL user-defined or REF parameter. In the - * case of a user-defined type the name is the type name of the parameter itself. For a REF - * parameter, the name is the type name of the referenced type. If a JDBC driver does not need - * the type code or type name information, it may ignore it.

+ *

Note: To be portable, applications must give the SQL type code and the + * fully-qualified SQL type name when specifying a NULL user-defined or REF parameter. In the case + * of a user-defined type the name is the type name of the parameter itself. For a REF parameter, + * the name is the type name of the referenced type. If a JDBC driver does not need the type code + * or type name information, it may ignore it. * - *

Although it is intended for user-defined and Ref parameters, this method may be used to set - * a - * null parameter of any JDBC type. If the parameter does not have a user-defined or REF type, the - * given typeName is ignored.

+ *

Although it is intended for user-defined and Ref parameters, this method may be used to set + * a null parameter of any JDBC type. If the parameter does not have a user-defined or REF type, + * the given typeName is ignored. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param sqlType a value from java.sql.Types - * @param typeName the fully-qualified name of an SQL user-defined type; ignored if the - * parameter is not a user-defined type or REF - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param sqlType a value from java.sql.Types + * @param typeName the fully-qualified name of an SQL user-defined type; ignored if the parameter + * is not a user-defined type or REF + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setNull(final int parameterIndex, final int sqlType, final String typeName) throws SQLException { @@ -692,15 +643,13 @@ public abstract void setParameter(final int parameterIndex, final ParameterHolde /** * Sets the designated parameter to the given java.net.URL value. The driver converts - * this to an SQL - * DATALINK value when it sends it to the database. + * this to an SQL DATALINK value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param url the java.net.URL object to be set - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param url the java.net.URL object to be set + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ @Override public void setURL(final int parameterIndex, final URL url) throws SQLException { @@ -716,24 +665,23 @@ public void setURL(final int parameterIndex, final URL url) throws SQLException * parameters. * * @return a ParameterMetaData object that contains information about the number, - * types and properties for each parameter marker of this PreparedStatement object + * types and properties for each parameter marker of this PreparedStatement + * object * @throws SQLException if a database access error occurs or this method is called on a closed - * PreparedStatement + * PreparedStatement * @see ParameterMetaData */ public abstract ParameterMetaData getParameterMetaData() throws SQLException; /** * Sets the designated parameter to the given java.sql.RowId object. The driver - * converts this to a SQL - * ROWID value when it sends it to the database + * converts this to a SQL ROWID value when it sends it to the database * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param rowid the parameter value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param rowid the parameter value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setRowId(final int parameterIndex, final RowId rowid) throws SQLException { throw ExceptionMapper.getFeatureNotSupportedException("RowIDs not supported"); @@ -741,19 +689,16 @@ public void setRowId(final int parameterIndex, final RowId rowid) throws SQLExce /** * Sets the designated paramter to the given String object. The driver converts this - * to a SQL - * NCHAR or NVARCHAR or LONGNVARCHAR value (depending on - * the argument's size relative to the driver's limits on NVARCHAR values) when it - * sends it to the database. + * to a SQL NCHAR or NVARCHAR or LONGNVARCHAR value + * (depending on the argument's size relative to the driver's limits on NVARCHAR + * values) when it sends it to the database. * * @param parameterIndex of the first parameter is 1, the second is 2, ... - * @param value the parameter value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if the driver does not - * support national character sets; if the driver can - * detect that a data conversion error could occur; if a - * database access error occurs; or this method is called - * on a closed PreparedStatement + * @param value the parameter value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if the driver does not support national character sets; if the driver can detect + * that a data conversion error could occur; if a database access error occurs; or this method + * is called on a closed PreparedStatement */ public void setNString(final int parameterIndex, final String value) throws SQLException { setString(parameterIndex, value); @@ -765,41 +710,35 @@ public void setNString(final int parameterIndex, final String value) throws SQLE * character format to the national character set in the database. * * @param parameterIndex of the first parameter is 1, the second is 2, ... - * @param value the parameter value - * @param length the number of characters in the parameter data. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if the driver does not - * support national character sets; if the driver can - * detect that a data conversion error could occur; if a - * database access error occurs; or this method is called - * on a closed PreparedStatement + * @param value the parameter value + * @param length the number of characters in the parameter data. + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if the driver does not support national character sets; if the driver can detect + * that a data conversion error could occur; if a database access error occurs; or this method + * is called on a closed PreparedStatement */ public void setNCharacterStream(final int parameterIndex, final Reader value, final long length) throws SQLException { setCharacterStream(parameterIndex, value, length); } - /** * Sets the designated parameter to a Reader object. The Reader reads * the data till end-of-file is reached. The driver does the necessary conversion from Java * character format to the national character set in the database. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * - *

Note: Consult your JDBC driver - * documentation to determine if it might be more efficient to use a version of - * setNCharacterStream which takes a length parameter.

+ *

Note: Consult your JDBC driver documentation to determine if it might be more + * efficient to use a version of setNCharacterStream which takes a length parameter. * * @param parameterIndex of the first parameter is 1, the second is 2, ... - * @param value the parameter value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if the driver does not - * support national character sets; if the driver can - * detect that a data conversion error could occur; if a - * database access error occurs; or this method is called - * on a closed PreparedStatement + * @param value the parameter value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if the driver does not support national character sets; if the driver can detect + * that a data conversion error could occur; if a database access error occurs; or this method + * is called on a closed PreparedStatement */ public void setNCharacterStream(final int parameterIndex, final Reader value) throws SQLException { @@ -808,94 +747,75 @@ public void setNCharacterStream(final int parameterIndex, final Reader value) /** * Sets the designated parameter to a java.sql.NClob object. The driver converts this - * to a SQL - * NCLOB value when it sends it to the database. + * to a SQL NCLOB value when it sends it to the database. * * @param parameterIndex of the first parameter is 1, the second is 2, ... - * @param value the parameter value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if the driver does not - * support national character sets; if the driver can - * detect that a data conversion error could occur; if a - * database access error occurs; or this method is called - * on a closed PreparedStatement + * @param value the parameter value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if the driver does not support national character sets; if the driver can detect + * that a data conversion error could occur; if a database access error occurs; or this method + * is called on a closed PreparedStatement */ public void setNClob(final int parameterIndex, final NClob value) throws SQLException { setClob(parameterIndex, value); } /** - * Sets the designated parameter to a Reader object. The reader must contain the + * Sets the designated parameter to a Reader object. The reader must contain the * number of characters specified by length otherwise a SQLException will be - * generated when the - * PreparedStatement is executed. This method differs from the + * generated when the PreparedStatement is executed. This method differs from the * setCharacterStream (int, Reader, * int) method because it informs the driver that the parameter value should be sent to the - * server as a - * NCLOB. When the setCharacterStream method is used, the driver may - * have to do extra work to determine whether the parameter data should be sent to the server as - * a - * LONGNVARCHAR or a - * NCLOB + * server as a NCLOB. When the setCharacterStream method is used, the + * driver may have to do extra work to determine whether the parameter data should be sent to the + * server as a LONGNVARCHAR or a NCLOB * * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param reader An object that contains the data to set the parameter value to. - * @param length the number of characters in the parameter data. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if the length specified is - * less than zero; if the driver does not support national - * character sets; if the driver can detect that a data - * conversion error could occur; if a database access - * error occurs or this method is called on a closed - * PreparedStatement + * @param reader An object that contains the data to set the parameter value to. + * @param length the number of characters in the parameter data. + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if the length specified is less than zero; if the driver does not support + * national character sets; if the driver can detect that a data conversion error could occur; + * if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setNClob(final int parameterIndex, final Reader reader, final long length) throws SQLException { setClob(parameterIndex, reader, length); } - /** * Sets the designated parameter to a Reader object. This method differs from the * setCharacterStream (int, Reader) method because it informs the driver that the - * parameter value should be sent to the server as a NCLOB. When the - * setCharacterStream method is used, the driver may have to do extra work to - * determine whether the parameter data should be sent to the server as a - * LONGNVARCHAR or a NCLOB + * parameter value should be sent to the server as a NCLOB. When the + * setCharacterStream method is used, the driver may have to do extra work to determine + * whether the parameter data should be sent to the server as a LONGNVARCHAR or a + * NCLOB * - *

Note: Consult your JDBC driver - * documentation to determine if it might be more efficient to use a version of - * setNClob which takes a length parameter.

+ *

Note: Consult your JDBC driver documentation to determine if it might be more + * efficient to use a version of setNClob which takes a length parameter. * * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param reader An object that contains the data to set the parameter value to. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if the driver does not - * support national character sets; if the driver can - * detect that a data conversion error could occur; if a - * database access error occurs or this method is called - * on a closed PreparedStatement + * @param reader An object that contains the data to set the parameter value to. + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if the driver does not support national character sets; if the driver can detect + * that a data conversion error could occur; if a database access error occurs or this method + * is called on a closed PreparedStatement */ public void setNClob(final int parameterIndex, final Reader reader) throws SQLException { setClob(parameterIndex, reader); } - /** * Sets the designated parameter to the given java.sql.SQLXML object. The driver - * converts this to an SQL XML value when it sends it to the database. - *
+ * converts this to an SQL XML value when it sends it to the database.
* * @param parameterIndex index of the first parameter is 1, the second is 2, ... - * @param xmlObject a SQLXML object that maps an SQL XML value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs; this method is called on a closed - * PreparedStatement or the - * java.xml.transform.Result, - * Writer or OutputStream has - * not been closed for the - * SQLXML object + * @param xmlObject a SQLXML object that maps an SQL XML value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs; this method is called on a closed + * PreparedStatement or the java.xml.transform.Result, Writer + * or OutputStream has not been closed for the SQLXML object */ @Override public void setSQLXML(final int parameterIndex, final SQLXML xmlObject) throws SQLException { @@ -903,63 +823,58 @@ public void setSQLXML(final int parameterIndex, final SQLXML xmlObject) throws S } /** - *

Sets the value of the designated parameter with the given object. The second argument must - * be an object type; for integral values, the java.lang equivalent objects should be - * used.

+ * Sets the value of the designated parameter with the given object. The second argument must be + * an object type; for integral values, the java.lang equivalent objects should be + * used. * - *

If the second argument is an InputStream then the stream must contain the number - * of bytes specified by scaleOrLength. If the second argument is a Reader then the - * reader must contain the number of characters specified by scaleOrLength. If these conditions - * are not true the driver will generate a - * SQLException when the prepared statement is executed.

+ *

If the second argument is an InputStream then the stream must contain the + * number of bytes specified by scaleOrLength. If the second argument is a Reader + * then the reader must contain the number of characters specified by scaleOrLength. If these + * conditions are not true the driver will generate a SQLException when the prepared + * statement is executed. * - *

The given Java object will be converted to the given targetSqlType before being sent to the - * database.

+ *

The given Java object will be converted to the given targetSqlType before being sent to the + * database. * - *

If the object has a custom mapping (is of a class implementing the interface - * SQLData), the JDBC driver should call the method SQLData.writeSQL to - * write it to the SQL data stream. If, on the other hand, the object is of a class implementing - * Ref, Blob, Clob, - * NClob, Struct, java.net.URL, or Array, the - * driver should pass it to the database as a value of the corresponding SQL type.

+ *

If the object has a custom mapping (is of a class implementing the interface SQLData + * ), the JDBC driver should call the method SQLData.writeSQL to write it to + * the SQL data stream. If, on the other hand, the object is of a class implementing Ref + * , Blob, Clob, NClob, Struct, + * java.net.URL, or Array, the driver should pass it to the database as a + * value of the corresponding SQL type. * - *

Note that this method may be used to pass database-specific abstract data types.

+ *

Note that this method may be used to pass database-specific abstract data types. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param obj the object containing the input parameter value - * @param targetSqlType the SQL type (as defined in java.sql.Types) to be sent to the database. - * The scale argument may further qualify this type. - * @param scaleOrLength for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC + * @param obj the object containing the input parameter value + * @param targetSqlType the SQL type (as defined in java.sql.Types) to be sent to the database. + * The scale argument may further qualify this type. + * @param scaleOrLength for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC * types, this is the number of digits after the decimal point. For - * Java Object types - * InputStream and Reader, this is the length of - * the data in the stream or reader. For all other types, this value will - * be ignored. - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs; this method is called on a closed - * PreparedStatement or if the Java Object - * specified by x is an InputStream or Reader object and - * the value of the scale parameter is less than zero + * Java Object types InputStream and Reader, this is the length of + * the data in the stream or reader. For all other types, this value will be ignored. + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs; this method is called on a closed + * PreparedStatement or if the Java Object specified by x is an InputStream or Reader + * object and the value of the scale parameter is less than zero * @see Types */ - public void setObject(final int parameterIndex, final Object obj, final int targetSqlType, - final int scaleOrLength) throws SQLException { + public void setObject( + final int parameterIndex, final Object obj, final int targetSqlType, final int scaleOrLength) + throws SQLException { setInternalObject(parameterIndex, obj, targetSqlType, scaleOrLength); } /** * Sets the value of the designated parameter with the given object. This method is like the - * method - * setObject above, except that it assumes a scale of zero. + * method setObject above, except that it assumes a scale of zero. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param obj the object containing the input parameter value - * @param targetSqlType the SQL type (as defined in java.sql.Types) to be sent to the database - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatements + * @param obj the object containing the input parameter value + * @param targetSqlType the SQL type (as defined in java.sql.Types) to be sent to the database + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatements * @see Types */ public void setObject(final int parameterIndex, final Object obj, final int targetSqlType) @@ -968,22 +883,19 @@ public void setObject(final int parameterIndex, final Object obj, final int targ } /** - *

Sets the value of the designated parameter using the given object. The second parameter - * must be of type - * Object; therefore, the java.lang equivalent objects should be used - * for built-in types.

+ * Sets the value of the designated parameter using the given object. The second parameter must be + * of type Object; therefore, the java.lang equivalent objects should be + * used for built-in types. * *

The JDBC specification specifies a standard mapping from Java Object types to - * SQL types. The given argument will be converted to the corresponding SQL type before being - * sent to the database.

+ * SQL types. The given argument will be converted to the corresponding SQL type before being sent + * to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param obj the object containing the input parameter value + * @param obj the object containing the input parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs; this method is called on a - * closed - * PreparedStatement or the type of the given object is - * ambiguous + * statement; if a database access error occurs; this method is called on a closed + * PreparedStatement or the type of the given object is ambiguous */ public void setObject(final int parameterIndex, final Object obj) throws SQLException { if (obj == null) { @@ -1033,30 +945,30 @@ public void setObject(final int parameterIndex, final Object obj) throws SQLExce } else if (obj instanceof LocalDate) { setDate(parameterIndex, Date.valueOf((LocalDate) obj)); } else if (obj instanceof OffsetDateTime) { - setParameter(parameterIndex, + setParameter( + parameterIndex, new ZonedDateTimeParameter( ((OffsetDateTime) obj).toZonedDateTime(), protocol.getTimeZone().toZoneId(), useFractionalSeconds, options)); } else if (obj instanceof OffsetTime) { - setParameter(parameterIndex, + setParameter( + parameterIndex, new OffsetTimeParameter( - (OffsetTime) obj, - protocol.getTimeZone().toZoneId(), - useFractionalSeconds, - options)); + (OffsetTime) obj, protocol.getTimeZone().toZoneId(), useFractionalSeconds, options)); } else if (obj instanceof ZonedDateTime) { - setParameter(parameterIndex, + setParameter( + parameterIndex, new ZonedDateTimeParameter( - (ZonedDateTime) obj, + (ZonedDateTime) obj, protocol.getTimeZone().toZoneId(), useFractionalSeconds, options)); } else if (obj instanceof LocalTime) { setParameter(parameterIndex, new LocalTimeParameter((LocalTime) obj, useFractionalSeconds)); } else { - //fallback to sending serialized object + // fallback to sending serialized object setParameter(parameterIndex, new SerializableParameter(obj, noBackslashEscapes)); hasLongData = true; } @@ -1073,9 +985,9 @@ public void setObject(int parameterIndex, Object obj, SQLType targetSqlType) thr setObject(parameterIndex, obj, targetSqlType.getVendorTypeNumber()); } - private void setInternalObject(final int parameterIndex, final Object obj, - final int targetSqlType, - final long scaleOrLength) throws SQLException { + private void setInternalObject( + final int parameterIndex, final Object obj, final int targetSqlType, final long scaleOrLength) + throws SQLException { switch (targetSqlType) { case Types.ARRAY: case Types.DATALINK: @@ -1146,7 +1058,8 @@ private void setInternalObject(final int parameterIndex, final Object obj, setTime(parameterIndex, Time.valueOf((String) obj)); break; case Types.TIME_WITH_TIMEZONE: - setParameter(parameterIndex, + setParameter( + parameterIndex, new OffsetTimeParameter( OffsetTime.parse(str), protocol.getTimeZone().toZoneId(), @@ -1154,8 +1067,8 @@ private void setInternalObject(final int parameterIndex, final Object obj, options)); break; case Types.TIMESTAMP_WITH_TIMEZONE: - - setParameter(parameterIndex, + setParameter( + parameterIndex, new ZonedDateTimeParameter( ZonedDateTime.parse(str, SPEC_ISO_ZONED_DATE_TIME), protocol.getTimeZone().toZoneId(), @@ -1163,12 +1076,12 @@ private void setInternalObject(final int parameterIndex, final Object obj, options)); break; default: - throw ExceptionMapper - .getSqlException("Could not convert [" + str + "] to " + targetSqlType); + throw ExceptionMapper.getSqlException( + "Could not convert [" + str + "] to " + targetSqlType); } } catch (IllegalArgumentException e) { - throw ExceptionMapper - .getSqlException("Could not convert [" + str + "] to " + targetSqlType, e); + throw ExceptionMapper.getSqlException( + "Could not convert [" + str + "] to " + targetSqlType, e); } } else if (obj instanceof Number) { Number bd = (Number) obj; @@ -1210,21 +1123,21 @@ private void setInternalObject(final int parameterIndex, final Object obj, setString(parameterIndex, bd.toString()); break; default: - throw ExceptionMapper - .getSqlException("Could not convert [" + bd + "] to " + targetSqlType); - + throw ExceptionMapper.getSqlException( + "Could not convert [" + bd + "] to " + targetSqlType); } } else if (obj instanceof byte[]) { - if (targetSqlType == Types.BINARY || targetSqlType == Types.VARBINARY + if (targetSqlType == Types.BINARY + || targetSqlType == Types.VARBINARY || targetSqlType == Types.LONGVARBINARY) { setBytes(parameterIndex, (byte[]) obj); } else { - throw ExceptionMapper - .getSqlException("Can only convert a byte[] to BINARY, VARBINARY or LONGVARBINARY"); + throw ExceptionMapper.getSqlException( + "Can only convert a byte[] to BINARY, VARBINARY or LONGVARBINARY"); } } else if (obj instanceof Time) { - setTime(parameterIndex, (Time) obj); // it is just a string anyway + setTime(parameterIndex, (Time) obj); // it is just a string anyway } else if (obj instanceof Timestamp) { setTimestamp(parameterIndex, (Timestamp) obj); } else if (obj instanceof Date) { @@ -1255,23 +1168,23 @@ private void setInternalObject(final int parameterIndex, final Object obj, } else if (obj instanceof LocalDate) { setDate(parameterIndex, Date.valueOf((LocalDate) obj)); } else if (obj instanceof OffsetDateTime) { - setParameter(parameterIndex, + setParameter( + parameterIndex, new ZonedDateTimeParameter( ((OffsetDateTime) obj).toZonedDateTime(), protocol.getTimeZone().toZoneId(), useFractionalSeconds, options)); } else if (obj instanceof OffsetTime) { - setParameter(parameterIndex, + setParameter( + parameterIndex, new OffsetTimeParameter( - (OffsetTime) obj, - protocol.getTimeZone().toZoneId(), - useFractionalSeconds, - options)); + (OffsetTime) obj, protocol.getTimeZone().toZoneId(), useFractionalSeconds, options)); } else if (obj instanceof ZonedDateTime) { - setParameter(parameterIndex, + setParameter( + parameterIndex, new ZonedDateTimeParameter( - (ZonedDateTime) obj, + (ZonedDateTime) obj, protocol.getTimeZone().toZoneId(), useFractionalSeconds, options)); @@ -1279,7 +1192,9 @@ private void setInternalObject(final int parameterIndex, final Object obj, setParameter(parameterIndex, new LocalTimeParameter((LocalTime) obj, useFractionalSeconds)); } else { throw ExceptionMapper.getSqlException( - "Could not set parameter in setObject, could not convert: " + obj.getClass() + " to " + "Could not set parameter in setObject, could not convert: " + + obj.getClass() + + " to " + targetSqlType); } } @@ -1291,16 +1206,15 @@ private void setInternalObject(final int parameterIndex, final Object obj, * the stream as needed until end-of-file is reached. The JDBC driver will do any necessary * conversion from ASCII to the database char format. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param stream the Java input stream that contains the ASCII parameter value - * @param length the number of bytes in the stream + * @param stream the Java input stream that contains the ASCII parameter value + * @param length the number of bytes in the stream * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setAsciiStream(final int parameterIndex, final InputStream stream, final long length) throws SQLException { @@ -1315,28 +1229,24 @@ public void setAsciiStream(final int parameterIndex, final InputStream stream, f /** * This function reads up the entire stream and stores it in memory since we need to know the * length when sending it to the server use the corresponding method with a length parameter if - * memory is an issue - *
+ * memory is an issue
* Sets the designated parameter to the given input stream. When a very large ASCII value is input - * to a - * LONGVARCHAR parameter, it may be more practical to send it via a - * java.io.InputStream. - * Data will be read from the stream as needed until end-of-file is reached. The JDBC driver will - * do any necessary conversion from ASCII to the database char format. + * to a LONGVARCHAR parameter, it may be more practical to send it via a + * java.io.InputStream. Data will be read from the stream as needed until end-of-file is + * reached. The JDBC driver will do any necessary conversion from ASCII to the database char + * format. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * - *

Note: Consult your JDBC driver - * documentation to determine if it might be more efficient to use a version of - * setAsciiStream which takes a length parameter.

+ *

Note: Consult your JDBC driver documentation to determine if it might be more + * efficient to use a version of setAsciiStream which takes a length parameter. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param stream the Java input stream that contains the ASCII parameter value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param stream the Java input stream that contains the ASCII parameter value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setAsciiStream(final int parameterIndex, final InputStream stream) throws SQLException { @@ -1355,16 +1265,15 @@ public void setAsciiStream(final int parameterIndex, final InputStream stream) * the stream as needed until end-of-file is reached. The JDBC driver will do any necessary * conversion from ASCII to the database char format. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param stream the Java input stream that contains the ASCII parameter value - * @param length the number of bytes in the stream + * @param stream the Java input stream that contains the ASCII parameter value + * @param length the number of bytes in the stream * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setAsciiStream(final int parameterIndex, final InputStream stream, final int length) throws SQLException { @@ -1382,16 +1291,15 @@ public void setAsciiStream(final int parameterIndex, final InputStream stream, f * may be more practical to send it via a java.io.InputStream object. The data will * be read from the stream as needed until end-of-file is reached. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param stream the java input stream which contains the binary parameter value - * @param length the number of bytes in the stream + * @param stream the java input stream which contains the binary parameter value + * @param length the number of bytes in the stream * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setBinaryStream(final int parameterIndex, final InputStream stream, final long length) throws SQLException { @@ -1405,27 +1313,23 @@ public void setBinaryStream(final int parameterIndex, final InputStream stream, /** * This function reads up the entire stream and stores it in memory since we need to know the - * length when sending it to the server - *
+ * length when sending it to the server
* Sets the designated parameter to the given input stream. When a very large binary value is - * input to a - * LONGVARBINARY parameter, it may be more practical to send it via a - * java.io.InputStream - * object. The data will be read from the stream as needed until end-of-file is reached. + * input to a LONGVARBINARY parameter, it may be more practical to send it via a + * java.io.InputStream object. The data will be read from the stream as needed until + * end-of-file is reached. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * - *

Note: Consult your JDBC driver - * documentation to determine if it might be more efficient to use a version of - * setBinaryStream which takes a length parameter.

+ *

Note: Consult your JDBC driver documentation to determine if it might be more + * efficient to use a version of setBinaryStream which takes a length parameter. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param stream the java input stream which contains the binary parameter value - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param stream the java input stream which contains the binary parameter value + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setBinaryStream(final int parameterIndex, final InputStream stream) throws SQLException { @@ -1437,23 +1341,21 @@ public void setBinaryStream(final int parameterIndex, final InputStream stream) hasLongData = true; } - /** * Sets the designated parameter to the given input stream, which will have the specified number * of bytes. When a very large binary value is input to a LONGVARBINARY parameter, it * may be more practical to send it via a java.io.InputStream object. The data will * be read from the stream as needed until end-of-file is reached. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param stream the java input stream which contains the binary parameter value - * @param length the number of bytes in the stream + * @param stream the java input stream which contains the binary parameter value + * @param length the number of bytes in the stream * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setBinaryStream(final int parameterIndex, final InputStream stream, final int length) throws SQLException { @@ -1465,18 +1367,15 @@ public void setBinaryStream(final int parameterIndex, final InputStream stream, hasLongData = true; } - /** * Sets the designated parameter to the given Java boolean value. The driver converts - * this to an SQL BIT or BOOLEAN value when it sends it to the - * database. + * this to an SQL BIT or BOOLEAN value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param value the parameter value + * @param value the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setBoolean(final int parameterIndex, final boolean value) throws SQLException { setParameter(parameterIndex, new BooleanParameter(value)); @@ -1484,15 +1383,13 @@ public void setBoolean(final int parameterIndex, final boolean value) throws SQL /** * Sets the designated parameter to the given Java byte value. The driver converts - * this to an SQL - * TINYINT value when it sends it to the database. + * this to an SQL TINYINT value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param bit the parameter value + * @param bit the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setByte(final int parameterIndex, final byte bit) throws SQLException { setParameter(parameterIndex, new ByteParameter(bit)); @@ -1500,15 +1397,13 @@ public void setByte(final int parameterIndex, final byte bit) throws SQLExceptio /** * Sets the designated parameter to the given Java short value. The driver converts - * this to an SQL - * SMALLINT value when it sends it to the database. + * this to an SQL SMALLINT value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param value the parameter value + * @param value the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setShort(final int parameterIndex, final short value) throws SQLException { setParameter(parameterIndex, new ShortParameter(value)); @@ -1518,11 +1413,10 @@ public void setShort(final int parameterIndex, final short value) throws SQLExce * Set string parameter. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param str String + * @param str String * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setString(final int parameterIndex, final String str) throws SQLException { if (str == null) { @@ -1534,18 +1428,16 @@ public void setString(final int parameterIndex, final String str) throws SQLExce } /** - * Sets the designated parameter to the given Java array of bytes. The driver converts this to an - * SQL - * VARBINARY or LONGVARBINARY (depending on the argument's size + * Sets the designated parameter to the given Java array of bytes. The driver converts this to an + * SQL VARBINARY or LONGVARBINARY (depending on the argument's size * relative to the driver's limits on VARBINARY values) when it sends it to the * database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param bytes the parameter value + * @param bytes the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setBytes(final int parameterIndex, final byte[] bytes) throws SQLException { if (bytes == null) { @@ -1556,30 +1448,25 @@ public void setBytes(final int parameterIndex, final byte[] bytes) throws SQLExc setParameter(parameterIndex, new ByteArrayParameter(bytes, noBackslashEscapes)); } - /** * Sets the designated parameter to the given input stream, which will have the specified number - * of bytes. - *
+ * of bytes.
* When a very large Unicode value is input to a LONGVARCHAR parameter, it may be * more practical to send it via a java.io.InputStream object. The data will be read - * from the stream as needed until end-of-file is reached. The JDBC driver will do any necessary - * conversion from Unicode to the database char format. - *
+ * from the stream as needed until end-of-file is reached. The JDBC driver will do any necessary + * conversion from Unicode to the database char format.
* The byte format of the Unicode stream must be a Java UTF-8, as defined in the Java Virtual * Machine Specification. * - *

Note: This stream object can either be a standard Java stream object or your own - * subclass that implements the standard interface.

+ *

Note: This stream object can either be a standard Java stream object or your own + * subclass that implements the standard interface. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param x a java.io.InputStream object that contains the Unicode - * parameter value - * @param length the number of bytes in the stream - * @throws SQLException if parameterIndex does not correspond to a parameter - * marker in the SQL statement; if a database access error - * occurs or this method is called on a closed - * PreparedStatement + * @param x a java.io.InputStream object that contains the Unicode parameter value + * @param length the number of bytes in the stream + * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement * @deprecated deprecated */ public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) @@ -1598,15 +1485,13 @@ public void setInt(final int column, final int value) throws SQLException { /** * Sets the designated parameter to the given Java long value. The driver converts - * this to an SQL - * BIGINT value when it sends it to the database. + * this to an SQL BIGINT value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param value the parameter value + * @param value the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setLong(final int parameterIndex, final long value) throws SQLException { setParameter(parameterIndex, new LongParameter(value)); @@ -1614,15 +1499,13 @@ public void setLong(final int parameterIndex, final long value) throws SQLExcept /** * Sets the designated parameter to the given Java float value. The driver converts - * this to an SQL - * REAL value when it sends it to the database. + * this to an SQL REAL value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param value the parameter value + * @param value the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setFloat(final int parameterIndex, final float value) throws SQLException { setParameter(parameterIndex, new FloatParameter(value)); @@ -1630,15 +1513,13 @@ public void setFloat(final int parameterIndex, final float value) throws SQLExce /** * Sets the designated parameter to the given Java double value. The driver converts - * this to an SQL - * DOUBLE value when it sends it to the database. + * this to an SQL DOUBLE value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param value the parameter value + * @param value the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setDouble(final int parameterIndex, final double value) throws SQLException { setParameter(parameterIndex, new DoubleParameter(value)); @@ -1649,11 +1530,10 @@ public void setDouble(final int parameterIndex, final double value) throws SQLEx * converts this to an SQL NUMERIC value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... - * @param bigDecimal the parameter value + * @param bigDecimal the parameter value * @throws SQLException if parameterIndex does not correspond to a parameter marker in the SQL - * statement; if a database access error occurs or this method is called on a - * closed - * PreparedStatement + * statement; if a database access error occurs or this method is called on a closed + * PreparedStatement */ public void setBigDecimal(final int parameterIndex, final BigDecimal bigDecimal) throws SQLException { @@ -1664,5 +1544,4 @@ public void setBigDecimal(final int parameterIndex, final BigDecimal bigDecimal) setParameter(parameterIndex, new BigDecimalParameter(bigDecimal)); } - } diff --git a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java index 632f212a9..af4402a8f 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbDatabaseMetaData.java @@ -86,7 +86,7 @@ public class MariaDbDatabaseMetaData implements DatabaseMetaData { * Constructor. * * @param connection connection - * @param urlParser Url parser + * @param urlParser Url parser */ public MariaDbDatabaseMetaData(Connection connection, UrlParser urlParser) { this.connection = (MariaDbConnection) connection; @@ -222,28 +222,30 @@ private static int getImportedKeyAction(String actionKey) { /** * Get imported keys. * - * @param tableDef table definition - * @param tableName table name - * @param catalog catalog + * @param tableDef table definition + * @param tableName table name + * @param catalog catalog * @param connection connection * @return resultset resultset * @throws ParseException exception */ - private static ResultSet getImportedKeys(String tableDef, String tableName, String catalog, - MariaDbConnection connection) throws ParseException { + private static ResultSet getImportedKeys( + String tableDef, String tableName, String catalog, MariaDbConnection connection) + throws ParseException { String[] columnNames = { - "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", - "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", - "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", - "UPDATE_RULE", "DELETE_RULE", "FK_NAME", - "PK_NAME", "DEFERRABILITY" + "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", + "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", + "PK_NAME", "DEFERRABILITY" }; ColumnType[] columnTypes = { - ColumnType.VARCHAR, ColumnType.NULL, ColumnType.VARCHAR, - ColumnType.VARCHAR, ColumnType.VARCHAR, ColumnType.NULL, - ColumnType.VARCHAR, ColumnType.VARCHAR, ColumnType.SMALLINT, - ColumnType.SMALLINT, ColumnType.SMALLINT, ColumnType.VARCHAR, - ColumnType.NULL, ColumnType.SMALLINT}; + ColumnType.VARCHAR, ColumnType.NULL, ColumnType.VARCHAR, + ColumnType.VARCHAR, ColumnType.VARCHAR, ColumnType.NULL, + ColumnType.VARCHAR, ColumnType.VARCHAR, ColumnType.SMALLINT, + ColumnType.SMALLINT, ColumnType.SMALLINT, ColumnType.VARCHAR, + ColumnType.NULL, ColumnType.SMALLINT + }; String[] parts = tableDef.split("\n"); @@ -274,7 +276,7 @@ private static ResultSet getImportedKeys(String tableDef, String tableName, Stri int onUpdateReferenceAction = DatabaseMetaData.importedKeyRestrict; int onDeleteReferenceAction = DatabaseMetaData.importedKeyRestrict; - for (String referenceAction : new String[]{"RESTRICT", "CASCADE", "SET NULL", "NO ACTION"}) { + for (String referenceAction : new String[] {"RESTRICT", "CASCADE", "SET NULL", "NO ACTION"}) { if (part.contains("ON UPDATE " + referenceAction)) { onUpdateReferenceAction = getImportedKeyAction(referenceAction); } @@ -309,83 +311,86 @@ private static ResultSet getImportedKeys(String tableDef, String tableName, Stri String[][] arr = data.toArray(new String[0][]); /* Sort array by PKTABLE_CAT, PKTABLE_NAME, and KEY_SEQ.*/ - Arrays.sort(arr, (row1, row2) -> { - int result = row1[0].compareTo(row2[0]); //PKTABLE_CAT - if (result == 0) { - result = row1[2].compareTo(row2[2]); //PKTABLE_NAME - if (result == 0) { - result = row1[8].length() - row2[8].length(); // KEY_SEQ + Arrays.sort( + arr, + (row1, row2) -> { + int result = row1[0].compareTo(row2[0]); // PKTABLE_CAT if (result == 0) { - result = row1[8].compareTo(row2[8]); + result = row1[2].compareTo(row2[2]); // PKTABLE_NAME + if (result == 0) { + result = row1[8].length() - row2[8].length(); // KEY_SEQ + if (result == 0) { + result = row1[8].compareTo(row2[8]); + } + } } - } - } - return result; - }); + return result; + }); return SelectResultSet.createResultSet(columnNames, columnTypes, arr, connection.getProtocol()); } /** * Retrieves a description of the primary key columns that are referenced by the given table's - * foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, + * foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, * PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ. * - *

Each primary key column description has the following columns:

+ *

Each primary key column description has the following columns: * *

    - *
  1. PKTABLE_CAT String {@code =>} primary key table catalog being imported (may be - * null) - *
  2. PKTABLE_SCHEM String {@code =>} primary key table schema being imported (may be - * null) - *
  3. PKTABLE_NAME String {@code =>} primary key table name being imported - *
  4. PKCOLUMN_NAME String {@code =>} primary key column name being imported - *
  5. FKTABLE_CAT String {@code =>} foreign key table catalog (may be null) - *
  6. FKTABLE_SCHEM String {@code =>} foreign key table schema (may be null) - *
  7. FKTABLE_NAME String {@code =>} foreign key table name - *
  8. FKCOLUMN_NAME String {@code =>} foreign key column name - *
  9. KEY_SEQ short {@code =>} sequence number within a foreign key( a value of 1 - * represents the first column of the foreign key, a value of 2 would represent the second column - * within the foreign key). - *
  10. UPDATE_RULE short {@code =>} What happens to a foreign key when the primary key is - * updated: - *
      - *
    • importedNoAction - do not allow update of primary key if it has been imported - *
    • importedKeyCascade - change imported key to agree with primary key update - *
    • importedKeySetNull - change imported key to NULL if its primary key has been - * updated - *
    • importedKeySetDefault - change imported key to default values if its primary key has been - * updated - *
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) - *
    - *
  11. DELETE_RULE short {@code =>} What happens to the foreign key when primary is - * deleted. - *
      - *
    • importedKeyNoAction - do not allow delete of primary key if it has been imported - *
    • importedKeyCascade - delete rows that import a deleted key - *
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted - *
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) - *
    • importedKeySetDefault - change imported key to default if its primary key has been - * deleted - *
    - *
  12. FK_NAME String {@code =>} foreign key name (may be null) - *
  13. PK_NAME String {@code =>} primary key name (may be null) - *
  14. DEFERRABILITY short {@code =>} can the evaluation of foreign key constraints be - * deferred until commit - *
      - *
    • importedKeyInitiallyDeferred - see SQL92 for definition - *
    • importedKeyInitiallyImmediate - see SQL92 for definition - *
    • importedKeyNotDeferrable - see SQL92 for definition - *
    + *
  15. PKTABLE_CAT String {@code =>} primary key table catalog being imported (may be + * null) + *
  16. PKTABLE_SCHEM String {@code =>} primary key table schema being imported (may be + * null) + *
  17. PKTABLE_NAME String {@code =>} primary key table name being imported + *
  18. PKCOLUMN_NAME String {@code =>} primary key column name being imported + *
  19. FKTABLE_CAT String {@code =>} foreign key table catalog (may be null) + *
  20. FKTABLE_SCHEM String {@code =>} foreign key table schema (may be null + * ) + *
  21. FKTABLE_NAME String {@code =>} foreign key table name + *
  22. FKCOLUMN_NAME String {@code =>} foreign key column name + *
  23. KEY_SEQ short {@code =>} sequence number within a foreign key( a value of 1 + * represents the first column of the foreign key, a value of 2 would represent the second + * column within the foreign key). + *
  24. UPDATE_RULE short {@code =>} What happens to a foreign key when the primary key is + * updated: + *
      + *
    • importedNoAction - do not allow update of primary key if it has been imported + *
    • importedKeyCascade - change imported key to agree with primary key update + *
    • importedKeySetNull - change imported key to NULL if its primary key + * has been updated + *
    • importedKeySetDefault - change imported key to default values if its primary key + * has been updated + *
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) + *
    + *
  25. DELETE_RULE short {@code =>} What happens to the foreign key when primary is + * deleted. + *
      + *
    • importedKeyNoAction - do not allow delete of primary key if it has been imported + *
    • importedKeyCascade - delete rows that import a deleted key + *
    • importedKeySetNull - change imported key to NULL if its primary key has been + * deleted + *
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) + *
    • importedKeySetDefault - change imported key to default if its primary key has been + * deleted + *
    + *
  26. FK_NAME String {@code =>} foreign key name (may be null) + *
  27. PK_NAME String {@code =>} primary key name (may be null) + *
  28. DEFERRABILITY short {@code =>} can the evaluation of foreign key constraints be + * deferred until commit + *
      + *
    • importedKeyInitiallyDeferred - see SQL92 for definition + *
    • importedKeyInitiallyImmediate - see SQL92 for definition + *
    • importedKeyNotDeferrable - see SQL92 for definition + *
    *
* * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" - * retrieves those without a catalog; - * null means that the catalog name should not be used to narrow the - * search - * @param schema a schema name; must match the schema name as it is stored in the database; "" - * retrieves those without a schema; null means that the schema name - * should not be used to narrow the search - * @param table a table name; must match the table name as it is stored in the database + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schema a schema name; must match the schema name as it is stored in the database; "" + * retrieves those without a schema; null means that the schema name should not + * be used to narrow the search + * @param table a table name; must match the table name as it is stored in the database * @return ResultSet - each row is a primary key column description * @throws SQLException if a database access error occurs * @see #getExportedKeys @@ -427,49 +432,90 @@ public ResultSet getImportedKeys(String catalog, String schema, String table) private String dataTypeClause(String fullTypeColumnName) { Options options = urlParser.getOptions(); return " CASE data_type" - + " WHEN 'bit' THEN " + Types.BIT - + " WHEN 'tinyblob' THEN " + Types.VARBINARY - + " WHEN 'mediumblob' THEN " + Types.LONGVARBINARY - + " WHEN 'longblob' THEN " + Types.LONGVARBINARY - + " WHEN 'blob' THEN " + Types.LONGVARBINARY - + " WHEN 'tinytext' THEN " + Types.VARCHAR - + " WHEN 'mediumtext' THEN " + Types.LONGVARCHAR - + " WHEN 'longtext' THEN " + Types.LONGVARCHAR - + " WHEN 'text' THEN " + Types.LONGVARCHAR - + " WHEN 'date' THEN " + Types.DATE - + " WHEN 'datetime' THEN " + Types.TIMESTAMP - + " WHEN 'decimal' THEN " + Types.DECIMAL - + " WHEN 'double' THEN " + Types.DOUBLE - + " WHEN 'enum' THEN " + Types.VARCHAR - + " WHEN 'float' THEN " + Types.REAL - + " WHEN 'int' THEN IF( " + fullTypeColumnName + " like '%unsigned%', " + Types.INTEGER + + " WHEN 'bit' THEN " + + Types.BIT + + " WHEN 'tinyblob' THEN " + + Types.VARBINARY + + " WHEN 'mediumblob' THEN " + + Types.LONGVARBINARY + + " WHEN 'longblob' THEN " + + Types.LONGVARBINARY + + " WHEN 'blob' THEN " + + Types.LONGVARBINARY + + " WHEN 'tinytext' THEN " + + Types.VARCHAR + + " WHEN 'mediumtext' THEN " + + Types.LONGVARCHAR + + " WHEN 'longtext' THEN " + + Types.LONGVARCHAR + + " WHEN 'text' THEN " + + Types.LONGVARCHAR + + " WHEN 'date' THEN " + + Types.DATE + + " WHEN 'datetime' THEN " + + Types.TIMESTAMP + + " WHEN 'decimal' THEN " + + Types.DECIMAL + + " WHEN 'double' THEN " + + Types.DOUBLE + + " WHEN 'enum' THEN " + + Types.VARCHAR + + " WHEN 'float' THEN " + + Types.REAL + + " WHEN 'int' THEN IF( " + + fullTypeColumnName + + " like '%unsigned%', " + + Types.INTEGER + + "," + + Types.INTEGER + + ")" + + " WHEN 'bigint' THEN " + + Types.BIGINT + + " WHEN 'mediumint' THEN " + + Types.INTEGER + + " WHEN 'null' THEN " + + Types.NULL + + " WHEN 'set' THEN " + + Types.VARCHAR + + " WHEN 'smallint' THEN IF( " + + fullTypeColumnName + + " like '%unsigned%', " + + Types.SMALLINT + "," - + Types.INTEGER + ")" - + " WHEN 'bigint' THEN " + Types.BIGINT - + " WHEN 'mediumint' THEN " + Types.INTEGER - + " WHEN 'null' THEN " + Types.NULL - + " WHEN 'set' THEN " + Types.VARCHAR - + " WHEN 'smallint' THEN IF( " + fullTypeColumnName + " like '%unsigned%', " - + Types.SMALLINT + "," + Types.SMALLINT + ")" - + " WHEN 'varchar' THEN " + Types.VARCHAR - + " WHEN 'varbinary' THEN " + Types.VARBINARY - + " WHEN 'char' THEN " + Types.CHAR - + " WHEN 'binary' THEN " + Types.BINARY - + " WHEN 'time' THEN " + Types.TIME - + " WHEN 'timestamp' THEN " + Types.TIMESTAMP + + Types.SMALLINT + + ")" + + " WHEN 'varchar' THEN " + + Types.VARCHAR + + " WHEN 'varbinary' THEN " + + Types.VARBINARY + + " WHEN 'char' THEN " + + Types.CHAR + + " WHEN 'binary' THEN " + + Types.BINARY + + " WHEN 'time' THEN " + + Types.TIME + + " WHEN 'timestamp' THEN " + + Types.TIMESTAMP + " WHEN 'tinyint' THEN " + (options.tinyInt1isBit - ? "IF(" + fullTypeColumnName + " like 'tinyint(1)%'," + Types.BIT + "," + Types.TINYINT - + ") " : Types.TINYINT) + ? "IF(" + + fullTypeColumnName + + " like 'tinyint(1)%'," + + Types.BIT + + "," + + Types.TINYINT + + ") " + : Types.TINYINT) + " WHEN 'year' THEN " + (options.yearIsDateType ? Types.DATE : Types.SMALLINT) - + " ELSE " + Types.OTHER + + " ELSE " + + Types.OTHER + " END "; } private ResultSet executeQuery(String sql) throws SQLException { - Statement stmt = new MariaDbStatement(connection, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); + Statement stmt = + new MariaDbStatement(connection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); SelectResultSet rs = (SelectResultSet) stmt.executeQuery(sql); rs.setStatement(null); // bypass Hibernate statement tracking (CONJ-49) rs.setForceTableAlias(); @@ -488,15 +534,14 @@ private String escapeQuote(String value) { * catalogs is the equivalent to MariaDB schemas. * * @param columnName - column name in the information schema table - * @param catalog - catalog name. This driver does not (always) follow JDBC standard for - * following special values, due to ConnectorJ compatibility 1. empty string - * ("") - matches current catalog (i.e database). JDBC standard says only tables - * without catalog should be returned - such tables do not exist in MariaDB. If - * there is no current catalog, then empty string matches any catalog. 2. null - - * if nullCatalogMeansCurrent=true (which is the default), then the handling is - * the same as for "" . i.e return current catalog.JDBC-conforming way would be - * to match any catalog with null parameter. This can be switched with - * nullCatalogMeansCurrent=false in the connection URL. + * @param catalog - catalog name. This driver does not (always) follow JDBC standard for following + * special values, due to ConnectorJ compatibility 1. empty string ("") - matches current + * catalog (i.e database). JDBC standard says only tables without catalog should be returned - + * such tables do not exist in MariaDB. If there is no current catalog, then empty string + * matches any catalog. 2. null - if nullCatalogMeansCurrent=true (which is the default), then + * the handling is the same as for "" . i.e return current catalog.JDBC-conforming way would + * be to match any catalog with null parameter. This can be switched with + * nullCatalogMeansCurrent=false in the connection URL. * @return part of SQL query ,that restricts search for the catalog. */ private String catalogCond(String columnName, String catalog) { @@ -511,10 +556,10 @@ private String catalogCond(String columnName, String catalog) { return "(ISNULL(database()) OR (" + columnName + " = database()))"; } return "(" + columnName + " = " + escapeQuote(catalog) + ")"; - } - // Helper to generate information schema queries with "like" or "equals" condition (typically on table name) + // Helper to generate information schema queries with "like" or "equals" condition (typically on + // table name) private String patternCond(String columnName, String tableName) { if (tableName == null) { return "(1 = 1)"; @@ -525,35 +570,34 @@ private String patternCond(String columnName, String tableName) { } /** - * Retrieves a description of the given table's primary key columns. They are ordered by + * Retrieves a description of the given table's primary key columns. They are ordered by * COLUMN_NAME. * - *

Each primary key column description has the following columns:

+ *

Each primary key column description has the following columns: * *

    - *
  1. TABLE_CAT String {@code =>} table catalog
  2. - *
  3. TABLE_SCHEM String {@code =>} table schema (may be null)
  4. - *
  5. TABLE_NAME String {@code =>} table name
  6. - *
  7. COLUMN_NAME String {@code =>} column name
  8. - *
  9. KEY_SEQ short {@code =>} sequence number within primary key( a value of 1 - * represents the first column of the primary key, a value of 2 would represent the second column - * within the primary key).
  10. - *
  11. PK_NAME String {@code =>} primary key name
  12. + *
  13. TABLE_CAT String {@code =>} table catalog + *
  14. TABLE_SCHEM String {@code =>} table schema (may be null) + *
  15. TABLE_NAME String {@code =>} table name + *
  16. COLUMN_NAME String {@code =>} column name + *
  17. KEY_SEQ short {@code =>} sequence number within primary key( a value of 1 + * represents the first column of the primary key, a value of 2 would represent the second + * column within the primary key). + *
  18. PK_NAME String {@code =>} primary key name *
* * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" - * retrieves those without a catalog; - * null means that the catalog name should not be used to narrow the - * search - * @param schema a schema name; must match the schema name as it is stored in the database; "" - * retrieves those without a schema; null means that the schema name - * should not be used to narrow the search - * @param table a table name; must match the table name as it is stored in the database + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schema a schema name; must match the schema name as it is stored in the database; "" + * retrieves those without a schema; null means that the schema name should not + * be used to narrow the search + * @param table a table name; must match the table name as it is stored in the database * @return ResultSet - each row is a primary key column description * @throws SQLException if a database access error occurs */ public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { - //MySQL 8 now use 'PRI' in place of 'pri' + // MySQL 8 now use 'PRI' in place of 'pri' String sql = "SELECT A.TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, A.TABLE_NAME, A.COLUMN_NAME, B.SEQ_IN_INDEX KEY_SEQ, B.INDEX_NAME PK_NAME " + " FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.STATISTICS B" @@ -570,12 +614,11 @@ public ResultSet getPrimaryKeys(String catalog, String schema, String table) thr + " ORDER BY A.COLUMN_NAME"; return executeQuery(sql); - } /** - * Maps standard table types to MariaDB ones - helper since table type is never "table" in MariaDB, it - * is "base table". + * Maps standard table types to MariaDB ones - helper since table type is never "table" in + * MariaDB, it is "base table". * * @param tableType the table type defined by user * @return the internal table type. @@ -589,58 +632,57 @@ private String mapTableTypes(String tableType) { /** * Retrieves a description of the tables available in the given catalog. Only table descriptions - * matching the catalog, schema, table name and type criteria are returned. They are ordered by - * TABLE_TYPE, TABLE_CAT, TABLE_SCHEM and - * TABLE_NAME. - * Each table description has the following columns: - *
  1. TABLE_CAT String {@code =>} - * table catalog (may be null) - *
  2. TABLE_SCHEM String {@code =>} table schema (may be null) - *
  3. TABLE_NAME String {@code =>} table name - *
  4. TABLE_TYPE String {@code =>} table type. Typical types are "TABLE", "VIEW", - * "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS - * String {@code =>} explanatory comment on the table - *
  6. TYPE_CAT String {@code =>} the types catalog (may be null) - *
  7. TYPE_SCHEM String {@code =>} the types schema (may be null) - *
  8. TYPE_NAME String {@code =>} type name (may be null) - *
  9. SELF_REFERENCING_COL_NAME String {@code =>} name of the designated "identifier" - * column of a typed table (may be null)
  10. REF_GENERATION String {@code =>} - * specifies how values in SELF_REFERENCING_COL_NAME are created. Values are "SYSTEM", "USER", - * "DERIVED". (may be null)
- * - *

Note: Some databases may not return information for all tables.

- * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used to - * narrow the search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored in - * the database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search + * matching the catalog, schema, table name and type criteria are returned. They are ordered by + * TABLE_TYPE, TABLE_CAT, TABLE_SCHEM and TABLE_NAME + * . Each table description has the following columns: + * + *
    + *
  1. TABLE_CAT String {@code =>} table catalog (may be null) + *
  2. TABLE_SCHEM String {@code =>} table schema (may be null) + *
  3. TABLE_NAME String {@code =>} table name + *
  4. TABLE_TYPE String {@code =>} table type. Typical types are "TABLE", "VIEW", + * "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM". + *
  5. REMARKS String {@code =>} explanatory comment on the table + *
  6. TYPE_CAT String {@code =>} the types catalog (may be null) + *
  7. TYPE_SCHEM String {@code =>} the types schema (may be null) + *
  8. TYPE_NAME String {@code =>} type name (may be null) + *
  9. SELF_REFERENCING_COL_NAME String {@code =>} name of the designated "identifier" + * column of a typed table (may be null) + *
  10. REF_GENERATION String {@code =>} specifies how values in SELF_REFERENCING_COL_NAME + * are created. Values are "SYSTEM", "USER", "DERIVED". (may be null) + *
+ * + *

Note: Some databases may not return information for all tables. + * + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search * @param tableNamePattern a table name pattern; must match the table name as it is stored in the - * database - * @param types a list of table types, which must be from the list of table types - * returned from {@link #getTableTypes},to include; - * null returns all types + * database + * @param types a list of table types, which must be from the list of table types returned from + * {@link #getTableTypes},to include; null returns all types * @return ResultSet - each row is a table description * @throws SQLException if a database access error occurs * @see #getSearchStringEscape */ - public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, - String[] types) + public ResultSet getTables( + String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { StringBuilder sql = - new StringBuilder("SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME," - + " IF(TABLE_TYPE='BASE TABLE', 'TABLE', TABLE_TYPE) as TABLE_TYPE," - + " TABLE_COMMENT REMARKS, NULL TYPE_CAT, NULL TYPE_SCHEM, NULL TYPE_NAME, NULL SELF_REFERENCING_COL_NAME, " - + " NULL REF_GENERATION" - + " FROM INFORMATION_SCHEMA.TABLES " - + " WHERE " - + catalogCond("TABLE_SCHEMA", catalog) - + " AND " - + patternCond("TABLE_NAME", tableNamePattern)); + new StringBuilder( + "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME," + + " IF(TABLE_TYPE='BASE TABLE', 'TABLE', TABLE_TYPE) as TABLE_TYPE," + + " TABLE_COMMENT REMARKS, NULL TYPE_CAT, NULL TYPE_SCHEM, NULL TYPE_NAME, NULL SELF_REFERENCING_COL_NAME, " + + " NULL REF_GENERATION" + + " FROM INFORMATION_SCHEMA.TABLES " + + " WHERE " + + catalogCond("TABLE_SCHEMA", catalog) + + " AND " + + patternCond("TABLE_NAME", tableNamePattern)); if (types != null && types.length > 0) { sql.append(" AND TABLE_TYPE IN ("); @@ -665,120 +707,144 @@ public ResultSet getTables(String catalog, String schemaPattern, String tableNam /** * Retrieves a description of table columns available in the specified catalog. * - *

Only column descriptions matching the catalog, schema, table and column name criteria are - * returned. They are ordered by - * TABLE_CAT,TABLE_SCHEM, TABLE_NAME, and - * ORDINAL_POSITION.

- * - *

Each column description has the following columns:

- * - *
  1. TABLE_CAT String {@code - * =>} table catalog (may be null) - *
  2. TABLE_SCHEM String {@code =>} table schema (may be null) - *
  3. TABLE_NAME String {@code =>} table name - *
  4. COLUMN_NAME String {@code =>} column name
  5. DATA_TYPE int {@code =>} SQL - * type from java.sql.Types
  6. TYPE_NAME String {@code =>} Data source dependent type - * name, for a UDT the type name is fully qualified - *
  7. COLUMN_SIZE int {@code =>} column size.
  8. BUFFER_LENGTH is not used. - *
  9. DECIMAL_DIGITS int {@code =>} the number of fractional digits. Null is returned for - * data types where DECIMAL_DIGITS is not applicable.
  10. NUM_PREC_RADIX int {@code =>} - * Radix (typically either 10 or 2)
  11. NULLABLE int {@code =>} is NULL allowed.
    • - * columnNoNulls - might not allow NULL values
    • columnNullable - definitely - * allows - * NULL values
    • columnNullableUnknown - nullability unknown
    - *
  12. REMARKS String {@code =>} comment describing column - * (may be null)
  13. COLUMN_DEF String {@code =>} default value for the - * column, which should be interpreted as a string when the value is enclosed in single quotes - * (may be null)
  14. SQL_DATA_TYPE int {@code =>} unused - *
  15. SQL_DATETIME_SUB int {@code =>} unused
  16. CHAR_OCTET_LENGTH int {@code =>} - * for char types the maximum number of bytes in the column - *
  17. ORDINAL_POSITION int {@code =>} index of column in table (starting at 1) - *
  18. IS_NULLABLE String {@code =>} ISO rules are - * used to determine the nullability for a column.
    • YES --- if the column can - * include NULLs
    • NO --- if the column cannot include NULLs
    • empty string --- - * if the nullability for the column is unknown
  19. SCOPE_CATALOG String {@code =>} - * catalog of table that is the scope of a reference attribute (null if DATA_TYPE - * isn't REF)
  20. SCOPE_SCHEMA String {@code =>} schema of table that is the scope of a - * reference attribute (null if the DATA_TYPE isn't REF)
  21. SCOPE_TABLE - * String {@code =>} table name that this the scope of a reference attribute (null if - * the DATA_TYPE isn't REF) - *
  22. SOURCE_DATA_TYPE short {@code =>} source type of a distinct type or user-generated - * Ref type, SQL type from java.sql.Types (null if DATA_TYPE isn't DISTINCT or - * user-generated REF) - *
  23. IS_AUTOINCREMENT String {@code =>} Indicates whether this column is auto - * incremented
    • YES --- if the column is auto incremented
    • NO --- if the - * column is not auto incremented
    • empty string --- if it cannot be determined whether the - * column is auto incremented
  24. IS_GENERATEDCOLUMN String {@code =>} Indicates - * whether this is a generated column
    • YES --- if this a generated column
    • - * NO --- if this not a generated column
    • empty string --- if it cannot be - * determined whether this is a generated column
+ *

Only column descriptions matching the catalog, schema, table and column name criteria are + * returned. They are ordered by TABLE_CAT,TABLE_SCHEM, TABLE_NAME + * , and ORDINAL_POSITION. + * + *

Each column description has the following columns: + * + *

    + *
  1. TABLE_CAT String {@code =>} table catalog (may be null) + *
  2. TABLE_SCHEM String {@code =>} table schema (may be null) + *
  3. TABLE_NAME String {@code =>} table name + *
  4. COLUMN_NAME String {@code =>} column name + *
  5. DATA_TYPE int {@code =>} SQL type from java.sql.Types + *
  6. TYPE_NAME String {@code =>} Data source dependent type name, for a UDT the type + * name is fully qualified + *
  7. COLUMN_SIZE int {@code =>} column size. + *
  8. BUFFER_LENGTH is not used. + *
  9. DECIMAL_DIGITS int {@code =>} the number of fractional digits. Null is returned + * for data types where DECIMAL_DIGITS is not applicable. + *
  10. NUM_PREC_RADIX int {@code =>} Radix (typically either 10 or 2) + *
  11. NULLABLE int {@code =>} is NULL allowed. + *
      + *
    • columnNoNulls - might not allow NULL values + *
    • columnNullable - definitely allows NULL values + *
    • columnNullableUnknown - nullability unknown + *
    + *
  12. REMARKS String {@code =>} comment describing column (may be null) + *
  13. COLUMN_DEF String {@code =>} default value for the column, which should be + * interpreted as a string when the value is enclosed in single quotes (may be null + * ) + *
  14. SQL_DATA_TYPE int {@code =>} unused + *
  15. SQL_DATETIME_SUB int {@code =>} unused + *
  16. CHAR_OCTET_LENGTH int {@code =>} for char types the maximum number of bytes in the + * column + *
  17. ORDINAL_POSITION int {@code =>} index of column in table (starting at 1) + *
  18. IS_NULLABLE String {@code =>} ISO rules are used to determine the nullability for + * a column. + *
      + *
    • YES --- if the column can include NULLs + *
    • NO --- if the column cannot include NULLs + *
    • empty string --- if the nullability for the column is unknown + *
    + *
  19. SCOPE_CATALOG String {@code =>} catalog of table that is the scope of a reference + * attribute (null if DATA_TYPE isn't REF) + *
  20. SCOPE_SCHEMA String {@code =>} schema of table that is the scope of a reference + * attribute (null if the DATA_TYPE isn't REF) + *
  21. SCOPE_TABLE String {@code =>} table name that this the scope of a reference + * attribute (null if the DATA_TYPE isn't REF) + *
  22. SOURCE_DATA_TYPE short {@code =>} source type of a distinct type or user-generated + * Ref type, SQL type from java.sql.Types (null if DATA_TYPE isn't DISTINCT or + * user-generated REF) + *
  23. IS_AUTOINCREMENT String {@code =>} Indicates whether this column is auto + * incremented + *
      + *
    • YES --- if the column is auto incremented + *
    • NO --- if the column is not auto incremented + *
    • empty string --- if it cannot be determined whether the column is auto incremented + *
    + *
  24. IS_GENERATEDCOLUMN String {@code =>} Indicates whether this is a generated column + *
      + *
    • YES --- if this a generated column + *
    • NO --- if this not a generated column + *
    • empty string --- if it cannot be determined whether this is a generated column + *
    + *
* *

The COLUMN_SIZE column specifies the column size for the given column. For numeric data, - * this is the maximum precision. For character data, this is the length in characters. For + * this is the maximum precision. For character data, this is the length in characters. For * datetime datatypes, this is the length in characters of the String representation (assuming the * maximum allowed precision of the fractional seconds component). For binary data, this is the - * length in bytes. For the ROWID datatype, this is the length in bytes. Null is returned for - * data types where the column size is not applicable.

- * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used to - * narrow the search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored in - * the database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search - * @param tableNamePattern a table name pattern; must match the table name as it is stored in the - * database + * length in bytes. For the ROWID datatype, this is the length in bytes. Null is returned for data + * types where the column size is not applicable. + * + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search + * @param tableNamePattern a table name pattern; must match the table name as it is stored in the + * database * @param columnNamePattern a column name pattern; must match the column name as it is stored in - * the database + * the database * @return ResultSet - each row is a column description * @throws SQLException if a database access error occurs * @see #getSearchStringEscape */ - public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) + public ResultSet getColumns( + String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { Options options = urlParser.getOptions(); - String sql = "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, COLUMN_NAME," - + dataTypeClause("COLUMN_TYPE") + " DATA_TYPE," - + columnTypeClause(options) + " TYPE_NAME, " - + " CASE DATA_TYPE" - + " WHEN 'time' THEN " - + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 10, CAST(11 + DATETIME_PRECISION as signed integer))" : "10") - + " WHEN 'date' THEN 10" - + " WHEN 'datetime' THEN " - + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" : "19") - + " WHEN 'timestamp' THEN " - + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" : "19") - + (options.yearIsDateType ? "" : " WHEN 'year' THEN 5") - + " ELSE " - + " IF(NUMERIC_PRECISION IS NULL, LEAST(CHARACTER_MAXIMUM_LENGTH," + Integer.MAX_VALUE - + "), NUMERIC_PRECISION) " - + " END" - + " COLUMN_SIZE, 65535 BUFFER_LENGTH, " - - + " CONVERT (CASE DATA_TYPE" - + " WHEN 'year' THEN " + (options.yearIsDateType ? "NUMERIC_SCALE" : "0") - + " WHEN 'tinyint' THEN " + (options.tinyInt1isBit ? "0" : "NUMERIC_SCALE") - + " ELSE NUMERIC_SCALE END, UNSIGNED INTEGER) DECIMAL_DIGITS," - - + " 10 NUM_PREC_RADIX, IF(IS_NULLABLE = 'yes',1,0) NULLABLE,COLUMN_COMMENT REMARKS," - + " COLUMN_DEFAULT COLUMN_DEF, 0 SQL_DATA_TYPE, 0 SQL_DATETIME_SUB, " - + " LEAST(CHARACTER_OCTET_LENGTH," + Integer.MAX_VALUE + ") CHAR_OCTET_LENGTH," - + " ORDINAL_POSITION, IS_NULLABLE, NULL SCOPE_CATALOG, NULL SCOPE_SCHEMA, NULL SCOPE_TABLE, NULL SOURCE_DATA_TYPE," - + " IF(EXTRA = 'auto_increment','YES','NO') IS_AUTOINCREMENT, " - + " IF(EXTRA in ('VIRTUAL', 'PERSISTENT', 'VIRTUAL GENERATED', 'STORED GENERATED') ,'YES','NO') IS_GENERATEDCOLUMN " - + " FROM INFORMATION_SCHEMA.COLUMNS WHERE " - + catalogCond("TABLE_SCHEMA", catalog) - + " AND " - + patternCond("TABLE_NAME", tableNamePattern) - + " AND " - + patternCond("COLUMN_NAME", columnNamePattern) - + " ORDER BY TABLE_CAT, TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION"; + String sql = + "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, COLUMN_NAME," + + dataTypeClause("COLUMN_TYPE") + + " DATA_TYPE," + + columnTypeClause(options) + + " TYPE_NAME, " + + " CASE DATA_TYPE" + + " WHEN 'time' THEN " + + (datePrecisionColumnExist + ? "IF(DATETIME_PRECISION = 0, 10, CAST(11 + DATETIME_PRECISION as signed integer))" + : "10") + + " WHEN 'date' THEN 10" + + " WHEN 'datetime' THEN " + + (datePrecisionColumnExist + ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" + : "19") + + " WHEN 'timestamp' THEN " + + (datePrecisionColumnExist + ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" + : "19") + + (options.yearIsDateType ? "" : " WHEN 'year' THEN 5") + + " ELSE " + + " IF(NUMERIC_PRECISION IS NULL, LEAST(CHARACTER_MAXIMUM_LENGTH," + + Integer.MAX_VALUE + + "), NUMERIC_PRECISION) " + + " END" + + " COLUMN_SIZE, 65535 BUFFER_LENGTH, " + + " CONVERT (CASE DATA_TYPE" + + " WHEN 'year' THEN " + + (options.yearIsDateType ? "NUMERIC_SCALE" : "0") + + " WHEN 'tinyint' THEN " + + (options.tinyInt1isBit ? "0" : "NUMERIC_SCALE") + + " ELSE NUMERIC_SCALE END, UNSIGNED INTEGER) DECIMAL_DIGITS," + + " 10 NUM_PREC_RADIX, IF(IS_NULLABLE = 'yes',1,0) NULLABLE,COLUMN_COMMENT REMARKS," + + " COLUMN_DEFAULT COLUMN_DEF, 0 SQL_DATA_TYPE, 0 SQL_DATETIME_SUB, " + + " LEAST(CHARACTER_OCTET_LENGTH," + + Integer.MAX_VALUE + + ") CHAR_OCTET_LENGTH," + + " ORDINAL_POSITION, IS_NULLABLE, NULL SCOPE_CATALOG, NULL SCOPE_SCHEMA, NULL SCOPE_TABLE, NULL SOURCE_DATA_TYPE," + + " IF(EXTRA = 'auto_increment','YES','NO') IS_AUTOINCREMENT, " + + " IF(EXTRA in ('VIRTUAL', 'PERSISTENT', 'VIRTUAL GENERATED', 'STORED GENERATED') ,'YES','NO') IS_GENERATEDCOLUMN " + + " FROM INFORMATION_SCHEMA.COLUMNS WHERE " + + catalogCond("TABLE_SCHEMA", catalog) + + " AND " + + patternCond("TABLE_NAME", tableNamePattern) + + " AND " + + patternCond("COLUMN_NAME", columnNamePattern) + + " ORDER BY TABLE_CAT, TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION"; try { return executeQuery(sql); @@ -789,7 +855,6 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa } throw sqlException; } - } /** @@ -797,48 +862,62 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa * columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, * FKTABLE_NAME, and KEY_SEQ. * - *

Each foreign key column description has the following columns:

- * - *
  1. PKTABLE_CAT - * String {@code =>} primary key table catalog (may be null)
  2. PKTABLE_SCHEM - * String {@code =>} primary key table schema (may be null)
  3. PKTABLE_NAME - * String {@code =>} primary key table name - *
  4. PKCOLUMN_NAME String {@code =>} primary key column name
  5. FKTABLE_CAT - * String {@code =>} foreign key table catalog (may be null) being exported (may be - * null)
  6. FKTABLE_SCHEM String {@code =>} foreign key table schema (may be - * null) being exported (may be null)
  7. FKTABLE_NAME String - * {@code =>} foreign key table name being exported
  8. FKCOLUMN_NAME String {@code =>} - * foreign key column name being exported
  9. KEY_SEQ short {@code =>} sequence number - * within foreign key( a value of 1 represents the first column of the foreign key, a value of 2 - * would represent the second column within the foreign key).
  10. UPDATE_RULE short {@code - * =>} What happens to foreign key when primary is updated:
      - *
    • importedNoAction - do not allow update of primary key if it has been imported
    • - * importedKeyCascade - change imported key to agree with primary key update
    • - * importedKeySetNull - change imported key to NULL if its primary key has been - * updated
    • importedKeySetDefault - change imported key to default values if its primary key - * has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x - * compatibility)
  11. DELETE_RULE short {@code =>} What happens to the foreign key - * when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if - * it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • - * importedKeySetNull - change imported key to NULL if its primary key has been - * deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) - *
    • importedKeySetDefault - change imported key to default if its primary key has been - * deleted - *
  12. FK_NAME String {@code =>} foreign key name (may be - * null)
  13. PK_NAME String {@code =>} primary key name (may be - * null)
  14. DEFERRABILITY short {@code =>} can the evaluation of foreign key - * constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for - * definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • - * importedKeyNotDeferrable - see SQL92 for definition
+ *

Each foreign key column description has the following columns: + * + *

    + *
  1. PKTABLE_CAT String {@code =>} primary key table catalog (may be null) + *
  2. PKTABLE_SCHEM String {@code =>} primary key table schema (may be null + * ) + *
  3. PKTABLE_NAME String {@code =>} primary key table name + *
  4. PKCOLUMN_NAME String {@code =>} primary key column name + *
  5. FKTABLE_CAT String {@code =>} foreign key table catalog (may be null) + * being exported (may be null) + *
  6. FKTABLE_SCHEM String {@code =>} foreign key table schema (may be null + * ) being exported (may be null) + *
  7. FKTABLE_NAME String {@code =>} foreign key table name being exported + *
  8. FKCOLUMN_NAME String {@code =>} foreign key column name being exported + *
  9. KEY_SEQ short {@code =>} sequence number within foreign key( a value of 1 + * represents the first column of the foreign key, a value of 2 would represent the second + * column within the foreign key). + *
  10. UPDATE_RULE short {@code =>} What happens to foreign key when primary is updated: + *
      + *
    • importedNoAction - do not allow update of primary key if it has been imported + *
    • importedKeyCascade - change imported key to agree with primary key update + *
    • importedKeySetNull - change imported key to NULL if its primary key + * has been updated + *
    • importedKeySetDefault - change imported key to default values if its primary key + * has been updated + *
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) + *
    + *
  11. DELETE_RULE short {@code =>} What happens to the foreign key when primary is + * deleted. + *
      + *
    • importedKeyNoAction - do not allow delete of primary key if it has been imported + *
    • importedKeyCascade - delete rows that import a deleted key + *
    • importedKeySetNull - change imported key to NULL if its primary key + * has been deleted + *
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) + *
    • importedKeySetDefault - change imported key to default if its primary key has been + * deleted + *
    + *
  12. FK_NAME String {@code =>} foreign key name (may be null) + *
  13. PK_NAME String {@code =>} primary key name (may be null) + *
  14. DEFERRABILITY short {@code =>} can the evaluation of foreign key constraints be + * deferred until commit + *
      + *
    • importedKeyInitiallyDeferred - see SQL92 for definition + *
    • importedKeyInitiallyImmediate - see SQL92 for definition + *
    • importedKeyNotDeferrable - see SQL92 for definition + *
    + *
* * @param catalog a catalog name; must match the catalog name as it is stored in this database; "" - * retrieves those without a catalog; - * null means that the catalog name should not be used to narrow the - * search - * @param schema a schema name; must match the schema name as it is stored in the database; "" - * retrieves those without a schema; null means that the schema name - * should not be used to narrow the search - * @param table a table name; must match the table name as it is stored in this database + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schema a schema name; must match the schema name as it is stored in the database; "" + * retrieves those without a schema; null means that the schema name should not + * be used to narrow the search + * @param table a table name; must match the table name as it is stored in this database * @return a ResultSet object in which each row is a foreign key column description * @throws SQLException if a database access error occurs * @see #getImportedKeys @@ -868,7 +947,8 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) + " END DELETE_RULE," + " RC.CONSTRAINT_NAME FK_NAME," + " NULL PK_NAME," - + importedKeyNotDeferrable + " DEFERRABILITY" + + importedKeyNotDeferrable + + " DEFERRABILITY" + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" + " INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC" + " ON KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA" @@ -876,7 +956,8 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) + " WHERE " + catalogCond("KCU.REFERENCED_TABLE_SCHEMA", catalog) + " AND " - + " KCU.REFERENCED_TABLE_NAME = " + escapeQuote(table) + + " KCU.REFERENCED_TABLE_NAME = " + + escapeQuote(table) + " ORDER BY FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, KEY_SEQ"; return executeQuery(sql); @@ -886,7 +967,7 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) * GetImportedKeysUsingInformationSchema. * * @param catalog catalog - * @param table table + * @param table table * @return resultset * @throws SQLException exception */ @@ -915,7 +996,8 @@ public ResultSet getImportedKeysUsingInformationSchema(String catalog, String ta + " END DELETE_RULE," + " RC.CONSTRAINT_NAME FK_NAME," + " NULL PK_NAME," - + importedKeyNotDeferrable + " DEFERRABILITY" + + importedKeyNotDeferrable + + " DEFERRABILITY" + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" + " INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC" + " ON KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA" @@ -923,7 +1005,8 @@ public ResultSet getImportedKeysUsingInformationSchema(String catalog, String ta + " WHERE " + catalogCond("KCU.TABLE_SCHEMA", catalog) + " AND " - + " KCU.TABLE_NAME = " + escapeQuote(table) + + " KCU.TABLE_NAME = " + + escapeQuote(table) + " ORDER BY PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, KEY_SEQ"; return executeQuery(sql); @@ -933,7 +1016,7 @@ public ResultSet getImportedKeysUsingInformationSchema(String catalog, String ta * GetImportedKeysUsingShowCreateTable. * * @param catalog catalog - * @param table table + * @param table table * @return resultset * @throws Exception exception */ @@ -948,9 +1031,14 @@ public ResultSet getImportedKeysUsingShowCreateTable(String catalog, String tabl throw new IllegalArgumentException("table"); } - ResultSet rs = connection.createStatement().executeQuery("SHOW CREATE TABLE " - + MariaDbConnection.quoteIdentifier(catalog) + "." + MariaDbConnection - .quoteIdentifier(table)); + ResultSet rs = + connection + .createStatement() + .executeQuery( + "SHOW CREATE TABLE " + + MariaDbConnection.quoteIdentifier(catalog) + + "." + + MariaDbConnection.quoteIdentifier(table)); if (rs.next()) { String tableDef = rs.getString(2); return MariaDbDatabaseMetaData.getImportedKeys(tableDef, table, catalog, connection); @@ -962,44 +1050,52 @@ public ResultSet getImportedKeysUsingShowCreateTable(String catalog, String tabl * Retrieves a description of a table's optimal set of columns that uniquely identifies a row. * They are ordered by SCOPE. * - *

Each column description has the following columns:

- * - *
  1. SCOPE short {@code =>} - * actual scope of result
    • bestRowTemporary - very temporary, while using row
    • - * bestRowTransaction - valid for remainder of current transaction
    • bestRowSession - valid for - * remainder of current session
    - *
  2. COLUMN_NAME String {@code =>} column name
  3. DATA_TYPE int {@code =>} SQL - * data type from java.sql.Types
  4. TYPE_NAME String {@code =>} Data source dependent type - * name, for a UDT the type name is fully qualified - *
  5. COLUMN_SIZE int {@code =>} precision
  6. BUFFER_LENGTH int {@code =>} not - * used
  7. DECIMAL_DIGITS short {@code =>} scale - Null is returned for data types where - * DECIMAL_DIGITS is not applicable. - *
  8. PSEUDO_COLUMN short {@code =>} is this a pseudo column like an Oracle ROWID
      - *
    • bestRowUnknown - may or may not be pseudo column
    • bestRowNotPseudo - is NOT a pseudo - * column
    • bestRowPseudo - is a pseudo column
+ *

Each column description has the following columns: + * + *

    + *
  1. SCOPE short {@code =>} actual scope of result + *
      + *
    • bestRowTemporary - very temporary, while using row + *
    • bestRowTransaction - valid for remainder of current transaction + *
    • bestRowSession - valid for remainder of current session + *
    + *
  2. COLUMN_NAME String {@code =>} column name + *
  3. DATA_TYPE int {@code =>} SQL data type from java.sql.Types + *
  4. TYPE_NAME String {@code =>} Data source dependent type name, for a UDT the type + * name is fully qualified + *
  5. COLUMN_SIZE int {@code =>} precision + *
  6. BUFFER_LENGTH int {@code =>} not used + *
  7. DECIMAL_DIGITS short {@code =>} scale - Null is returned for data types where + * DECIMAL_DIGITS is not applicable. + *
  8. PSEUDO_COLUMN short {@code =>} is this a pseudo column like an Oracle ROWID + *
      + *
    • bestRowUnknown - may or may not be pseudo column + *
    • bestRowNotPseudo - is NOT a pseudo column + *
    • bestRowPseudo - is a pseudo column + *
    + *
* *

The COLUMN_SIZE column represents the specified column size for the given column. For - * numeric data, this is the maximum precision. For character data, this is the length in + * numeric data, this is the maximum precision. For character data, this is the length in * characters. For datetime datatypes, this is the length in characters of the String * representation (assuming the maximum allowed precision of the fractional seconds component). - * For binary data, this is the length in bytes. For the ROWID datatype, this is the length in - * bytes. Null is returned for data types where the column size is not applicable.

- * - * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" - * retrieves those without a catalog; - * null means that the catalog name should not be used to narrow the - * search - * @param schema a schema name; must match the schema name as it is stored in the database; "" - * retrieves those without a schema; null means that the schema name - * should not be used to narrow the search - * @param table a table name; must match the table name as it is stored in the database - * @param scope the scope of interest; use same values as SCOPE + * For binary data, this is the length in bytes. For the ROWID datatype, this is the length in + * bytes. Null is returned for data types where the column size is not applicable. + * + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schema a schema name; must match the schema name as it is stored in the database; "" + * retrieves those without a schema; null means that the schema name should not + * be used to narrow the search + * @param table a table name; must match the table name as it is stored in the database + * @param scope the scope of interest; use same values as SCOPE * @param nullable include columns that are nullable. * @return ResultSet - each row is a column description * @throws SQLException if a database access error occurs */ - public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, - final boolean nullable) + public ResultSet getBestRowIdentifier( + String catalog, String schema, String table, int scope, final boolean nullable) throws SQLException { if (table == null) { @@ -1007,8 +1103,11 @@ public ResultSet getBestRowIdentifier(String catalog, String schema, String tabl } String sql = - "SELECT " + DatabaseMetaData.bestRowUnknown + " SCOPE, COLUMN_NAME," - + dataTypeClause("COLUMN_TYPE") + " DATA_TYPE, DATA_TYPE TYPE_NAME," + "SELECT " + + DatabaseMetaData.bestRowUnknown + + " SCOPE, COLUMN_NAME," + + dataTypeClause("COLUMN_TYPE") + + " DATA_TYPE, DATA_TYPE TYPE_NAME," + " IF(NUMERIC_PRECISION IS NULL, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION) COLUMN_SIZE, 0 BUFFER_LENGTH," + " NUMERIC_SCALE DECIMAL_DIGITS," + " 1 PSEUDO_COLUMN" @@ -1016,7 +1115,8 @@ public ResultSet getBestRowIdentifier(String catalog, String schema, String tabl + " WHERE COLUMN_KEY IN('PRI', 'MUL', 'UNI')" + " AND " + catalogCond("TABLE_SCHEMA", catalog) - + " AND TABLE_NAME = " + escapeQuote(table); + + " AND TABLE_NAME = " + + escapeQuote(table); return executeQuery(sql); } @@ -1032,63 +1132,68 @@ public boolean generatedKeyAlwaysReturned() { * list. Pseudo or hidden columns may not necessarily be able to be modified. If there are no * pseudo or hidden columns, an empty ResultSet is returned. * - *

Only column descriptions matching the catalog, schema, table and column name criteria are - * returned. They are ordered by - * TABLE_CAT,TABLE_SCHEM, TABLE_NAME and - * COLUMN_NAME.

- * - *

Each column description has the following columns:

- * - *
  1. TABLE_CAT String {@code - * =>} table catalog (may be null) - *
  2. TABLE_SCHEM String {@code =>} table schema (may be null) - *
  3. TABLE_NAME String {@code =>} table name - *
  4. COLUMN_NAME String {@code =>} column name
  5. DATA_TYPE int {@code =>} SQL - * type from java.sql.Types
  6. COLUMN_SIZE int {@code =>} column size. - *
  7. DECIMAL_DIGITS int {@code =>} the number of fractional digits. Null is returned for - * data types where DECIMAL_DIGITS is not applicable. - *
  8. NUM_PREC_RADIX int {@code =>} Radix (typically either 10 or 2) - *
  9. COLUMN_USAGE String {@code =>} The allowed usage for the column. The value - * returned will correspond to the enum name returned by - * PseudoColumnUsage.name()
  10. REMARKS String {@code =>} comment describing column (may - * be null) - *
  11. CHAR_OCTET_LENGTH int {@code =>} for char types the maximum number of bytes in the - * column
  12. IS_NULLABLE String {@code =>} ISO rules are used to determine the - * nullability for a column.
    • YES --- if the column can include NULLs
    • NO - * --- if the column cannot include NULLs
    • empty string --- if the nullability for the column - * is unknown
+ *

Only column descriptions matching the catalog, schema, table and column name criteria are + * returned. They are ordered by TABLE_CAT,TABLE_SCHEM, TABLE_NAME + * and COLUMN_NAME. + * + *

Each column description has the following columns: + * + *

    + *
  1. TABLE_CAT String {@code =>} table catalog (may be null) + *
  2. TABLE_SCHEM String {@code =>} table schema (may be null) + *
  3. TABLE_NAME String {@code =>} table name + *
  4. COLUMN_NAME String {@code =>} column name + *
  5. DATA_TYPE int {@code =>} SQL type from java.sql.Types + *
  6. COLUMN_SIZE int {@code =>} column size. + *
  7. DECIMAL_DIGITS int {@code =>} the number of fractional digits. Null is returned + * for data types where DECIMAL_DIGITS is not applicable. + *
  8. NUM_PREC_RADIX int {@code =>} Radix (typically either 10 or 2) + *
  9. COLUMN_USAGE String {@code =>} The allowed usage for the column. The value + * returned will correspond to the enum name returned by PseudoColumnUsage.name() + *
  10. REMARKS String {@code =>} comment describing column (may be null) + *
  11. CHAR_OCTET_LENGTH int {@code =>} for char types the maximum number of bytes in the + * column + *
  12. IS_NULLABLE String {@code =>} ISO rules are used to determine the nullability for + * a column. + *
      + *
    • YES --- if the column can include NULLs + *
    • NO --- if the column cannot include NULLs + *
    • empty string --- if the nullability for the column is unknown + *
    + *
* *

The COLUMN_SIZE column specifies the column size for the given column. For numeric data, - * this is the maximum precision. For character data, this is the length in characters. For + * this is the maximum precision. For character data, this is the length in characters. For * datetime datatypes, this is the length in characters of the String representation (assuming the * maximum allowed precision of the fractional seconds component). For binary data, this is the - * length in bytes. For the ROWID datatype, this is the length in bytes. Null is returned for - * data types where the column size is not applicable.

- * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used to - * narrow the search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored in - * the database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search - * @param tableNamePattern a table name pattern; must match the table name as it is stored in the - * database + * length in bytes. For the ROWID datatype, this is the length in bytes. Null is returned for data + * types where the column size is not applicable. + * + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search + * @param tableNamePattern a table name pattern; must match the table name as it is stored in the + * database * @param columnNamePattern a column name pattern; must match the column name as it is stored in - * the database + * the database * @return ResultSet - each row is a column description * @throws SQLException if a database access error occurs * @see PseudoColumnUsage * @since 1.7 */ - public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) throws SQLException { - return connection.createStatement().executeQuery( - "SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM," - + "' ' TABLE_NAME, ' ' COLUMN_NAME, 0 DATA_TYPE, 0 COLUMN_SIZE, 0 DECIMAL_DIGITS," - + "10 NUM_PREC_RADIX, ' ' COLUMN_USAGE, ' ' REMARKS, 0 CHAR_OCTET_LENGTH, 'YES' IS_NULLABLE FROM DUAL " - + "WHERE 1=0"); + public ResultSet getPseudoColumns( + String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) + throws SQLException { + return connection + .createStatement() + .executeQuery( + "SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM," + + "' ' TABLE_NAME, ' ' COLUMN_NAME, 0 DATA_TYPE, 0 COLUMN_SIZE, 0 DECIMAL_DIGITS," + + "10 NUM_PREC_RADIX, ' ' COLUMN_USAGE, ' ' REMARKS, 0 CHAR_OCTET_LENGTH, 'YES' IS_NULLABLE FROM DUAL " + + "WHERE 1=0"); } public boolean allProceduresAreCallable() { @@ -1129,8 +1234,8 @@ public boolean nullsAreSortedAtEnd() { } /** - * Return Server type. - * MySQL or MariaDB. MySQL can be forced for compatibility with option "useMysqlMetadata" + * Return Server type. MySQL or MariaDB. MySQL can be forced for compatibility with option + * "useMysqlMetadata" * * @return server type * @throws SQLException in case of socket error. @@ -1140,7 +1245,11 @@ public String getDatabaseProductName() throws SQLException { return "MySQL"; } if (connection.getProtocol().isServerMariaDb() - && connection.getProtocol().getServerVersion().toLowerCase(Locale.ROOT).contains("mariadb")) { + && connection + .getProtocol() + .getServerVersion() + .toLowerCase(Locale.ROOT) + .contains("mariadb")) { return "MariaDB"; } return "MySQL"; @@ -1218,19 +1327,18 @@ public String getIdentifierQuoteString() { */ @Override public String getSQLKeywords() { - return - "ACCESSIBLE,ANALYZE,ASENSITIVE,BEFORE,BIGINT,BINARY,BLOB,CALL,CHANGE,CONDITION,DATABASE,DATABASES," - + "DAY_HOUR,DAY_MICROSECOND,DAY_MINUTE,DAY_SECOND,DELAYED,DETERMINISTIC,DISTINCTROW,DIV,DUAL,EACH," - + "ELSEIF,ENCLOSED,ESCAPED,EXIT,EXPLAIN,FLOAT4,FLOAT8,FORCE,FULLTEXT,GENERAL,HIGH_PRIORITY," - + "HOUR_MICROSECOND,HOUR_MINUTE,HOUR_SECOND,IF,IGNORE,IGNORE_SERVER_IDS,INDEX,INFILE,INOUT,INT1,INT2," - + "INT3,INT4,INT8,ITERATE,KEY,KEYS,KILL,LEAVE,LIMIT,LINEAR,LINES,LOAD,LOCALTIME,LOCALTIMESTAMP,LOCK," - + "LONG,LONGBLOB,LONGTEXT,LOOP,LOW_PRIORITY,MASTER_HEARTBEAT_PERIOD,MASTER_SSL_VERIFY_SERVER_CERT," - + "MAXVALUE,MEDIUMBLOB,MEDIUMINT,MEDIUMTEXT,MIDDLEINT,MINUTE_MICROSECOND,MINUTE_SECOND,MOD,MODIFIES," - + "NO_WRITE_TO_BINLOG,OPTIMIZE,OPTIONALLY,OUT,OUTFILE,PURGE,RANGE,READ_WRITE,READS,REGEXP,RELEASE," - + "RENAME,REPEAT,REPLACE,REQUIRE,RESIGNAL,RESTRICT,RETURN,RLIKE,SCHEMAS,SECOND_MICROSECOND,SENSITIVE," - + "SEPARATOR,SHOW,SIGNAL,SLOW,SPATIAL,SPECIFIC,SQL_BIG_RESULT,SQL_CALC_FOUND_ROWS,SQL_SMALL_RESULT," - + "SQLEXCEPTION,SSL,STARTING,STRAIGHT_JOIN,TERMINATED,TINYBLOB,TINYINT,TINYTEXT,TRIGGER,UNDO,UNLOCK," - + "UNSIGNED,USE,UTC_DATE,UTC_TIME,UTC_TIMESTAMP,VARBINARY,VARCHARACTER,WHILE,XOR,YEAR_MONTH,ZEROFILL"; + return "ACCESSIBLE,ANALYZE,ASENSITIVE,BEFORE,BIGINT,BINARY,BLOB,CALL,CHANGE,CONDITION,DATABASE,DATABASES," + + "DAY_HOUR,DAY_MICROSECOND,DAY_MINUTE,DAY_SECOND,DELAYED,DETERMINISTIC,DISTINCTROW,DIV,DUAL,EACH," + + "ELSEIF,ENCLOSED,ESCAPED,EXIT,EXPLAIN,FLOAT4,FLOAT8,FORCE,FULLTEXT,GENERAL,HIGH_PRIORITY," + + "HOUR_MICROSECOND,HOUR_MINUTE,HOUR_SECOND,IF,IGNORE,IGNORE_SERVER_IDS,INDEX,INFILE,INOUT,INT1,INT2," + + "INT3,INT4,INT8,ITERATE,KEY,KEYS,KILL,LEAVE,LIMIT,LINEAR,LINES,LOAD,LOCALTIME,LOCALTIMESTAMP,LOCK," + + "LONG,LONGBLOB,LONGTEXT,LOOP,LOW_PRIORITY,MASTER_HEARTBEAT_PERIOD,MASTER_SSL_VERIFY_SERVER_CERT," + + "MAXVALUE,MEDIUMBLOB,MEDIUMINT,MEDIUMTEXT,MIDDLEINT,MINUTE_MICROSECOND,MINUTE_SECOND,MOD,MODIFIES," + + "NO_WRITE_TO_BINLOG,OPTIMIZE,OPTIONALLY,OUT,OUTFILE,PURGE,RANGE,READ_WRITE,READS,REGEXP,RELEASE," + + "RENAME,REPEAT,REPLACE,REQUIRE,RESIGNAL,RESTRICT,RETURN,RLIKE,SCHEMAS,SECOND_MICROSECOND,SENSITIVE," + + "SEPARATOR,SHOW,SIGNAL,SLOW,SPATIAL,SPECIFIC,SQL_BIG_RESULT,SQL_CALC_FOUND_ROWS,SQL_SMALL_RESULT," + + "SQLEXCEPTION,SSL,STARTING,STRAIGHT_JOIN,TERMINATED,TINYBLOB,TINYINT,TINYTEXT,TRIGGER,UNDO,UNLOCK," + + "UNSIGNED,USE,UTC_DATE,UTC_TIME,UTC_TIMESTAMP,VARBINARY,VARCHARACTER,WHILE,XOR,YEAR_MONTH,ZEROFILL"; } /** @@ -1240,9 +1348,8 @@ public String getSQLKeywords() { */ @Override public String getNumericFunctions() { - return - "DIV,ABS,ACOS,ASIN,ATAN,ATAN2,CEIL,CEILING,CONV,COS,COT,CRC32,DEGREES,EXP,FLOOR,GREATEST,LEAST,LN,LOG," - + "LOG10,LOG2,MOD,OCT,PI,POW,POWER,RADIANS,RAND,ROUND,SIGN,SIN,SQRT,TAN,TRUNCATE"; + return "DIV,ABS,ACOS,ASIN,ATAN,ATAN2,CEIL,CEILING,CONV,COS,COT,CRC32,DEGREES,EXP,FLOOR,GREATEST,LEAST,LN,LOG," + + "LOG10,LOG2,MOD,OCT,PI,POW,POWER,RADIANS,RAND,ROUND,SIGN,SIN,SQRT,TAN,TRUNCATE"; } /** @@ -1252,12 +1359,11 @@ public String getNumericFunctions() { */ @Override public String getStringFunctions() { - return - "ASCII,BIN,BIT_LENGTH,CAST,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONVERT,ELT,EXPORT_SET," - + "EXTRACTVALUE,FIELD,FIND_IN_SET,FORMAT,FROM_BASE64,HEX,INSTR,LCASE,LEFT,LENGTH,LIKE,LOAD_FILE,LOCATE," - + "LOWER,LPAD,LTRIM,MAKE_SET,MATCH AGAINST,MID,NOT LIKE,NOT REGEXP,OCTET_LENGTH,ORD,POSITION,QUOTE," - + "REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SOUNDS LIKE,SPACE,STRCMP,SUBSTR,SUBSTRING," - + "SUBSTRING_INDEX,TO_BASE64,TRIM,UCASE,UNHEX,UPDATEXML,UPPER,WEIGHT_STRING"; + return "ASCII,BIN,BIT_LENGTH,CAST,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONVERT,ELT,EXPORT_SET," + + "EXTRACTVALUE,FIELD,FIND_IN_SET,FORMAT,FROM_BASE64,HEX,INSTR,LCASE,LEFT,LENGTH,LIKE,LOAD_FILE,LOCATE," + + "LOWER,LPAD,LTRIM,MAKE_SET,MATCH AGAINST,MID,NOT LIKE,NOT REGEXP,OCTET_LENGTH,ORD,POSITION,QUOTE," + + "REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SOUNDS LIKE,SPACE,STRCMP,SUBSTR,SUBSTRING," + + "SUBSTRING_INDEX,TO_BASE64,TRIM,UCASE,UNHEX,UPDATEXML,UPPER,WEIGHT_STRING"; } /** @@ -1277,13 +1383,12 @@ public String getSystemFunctions() { */ @Override public String getTimeDateFunctions() { - return - "ADDDATE,ADDTIME,CONVERT_TZ,CURDATE,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURTIME,DATEDIFF," - + "DATE_ADD,DATE_FORMAT,DATE_SUB,DAY,DAYNAME,DAYOFMONTH,DAYOFWEEK,DAYOFYEAR,EXTRACT,FROM_DAYS," - + "FROM_UNIXTIME,GET_FORMAT,HOUR,LAST_DAY,LOCALTIME,LOCALTIMESTAMP,MAKEDATE,MAKETIME,MICROSECOND," - + "MINUTE,MONTH,MONTHNAME,NOW,PERIOD_ADD,PERIOD_DIFF,QUARTER,SECOND,SEC_TO_TIME,STR_TO_DATE,SUBDATE," - + "SUBTIME,SYSDATE,TIMEDIFF,TIMESTAMPADD,TIMESTAMPDIFF,TIME_FORMAT,TIME_TO_SEC,TO_DAYS,TO_SECONDS," - + "UNIX_TIMESTAMP,UTC_DATE,UTC_TIME,UTC_TIMESTAMP,WEEK,WEEKDAY,WEEKOFYEAR,YEAR,YEARWEEK"; + return "ADDDATE,ADDTIME,CONVERT_TZ,CURDATE,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURTIME,DATEDIFF," + + "DATE_ADD,DATE_FORMAT,DATE_SUB,DAY,DAYNAME,DAYOFMONTH,DAYOFWEEK,DAYOFYEAR,EXTRACT,FROM_DAYS," + + "FROM_UNIXTIME,GET_FORMAT,HOUR,LAST_DAY,LOCALTIME,LOCALTIMESTAMP,MAKEDATE,MAKETIME,MICROSECOND," + + "MINUTE,MONTH,MONTHNAME,NOW,PERIOD_ADD,PERIOD_DIFF,QUARTER,SECOND,SEC_TO_TIME,STR_TO_DATE,SUBDATE," + + "SUBTIME,SYSDATE,TIMEDIFF,TIMESTAMPADD,TIMESTAMPDIFF,TIME_FORMAT,TIME_TO_SEC,TO_DAYS,TO_SECONDS," + + "UNIX_TIMESTAMP,UTC_DATE,UTC_TIME,UTC_TIMESTAMP,WEEK,WEEKDAY,WEEKOFYEAR,YEAR,YEARWEEK"; } public String getSearchStringEscape() { @@ -1315,8 +1420,9 @@ public boolean supportsConvert() { } /** - * Retrieves whether this database supports the JDBC scalar function CONVERT for conversions between the JDBC types - * fromType and toType. The JDBC types are the generic SQL data types defined in java.sql.Types. + * Retrieves whether this database supports the JDBC scalar function CONVERT for conversions + * between the JDBC types fromType and toType. The JDBC types are the generic SQL data types + * defined in java.sql.Types. * * @param fromType the type to convert from; one of the type codes from the class java.sql.Types * @param toType the type to convert to; one of the type codes from the class java.sql.Types @@ -1768,9 +1874,8 @@ public int getDefaultTransactionIsolation() { } /** - * Retrieves whether this database supports transactions. If not, invoking the method - * commit is a noop, and the isolation level is - * TRANSACTION_NONE. + * Retrieves whether this database supports transactions. If not, invoking the method commit + * is a noop, and the isolation level is TRANSACTION_NONE. * * @return true if transactions are supported; false otherwise */ @@ -1778,14 +1883,14 @@ public boolean supportsTransactions() { return true; } - /* Helper to generate information schema with "equality" condition (typically on catalog name) */ /** * Retrieves whether this database supports the given transaction isolation level. * - * @param level one of the transaction isolation levels defined in java.sql.Connection + * @param level one of the transaction isolation levels defined in java.sql.Connection + * * @return true if so; false otherwise * @see Connection */ @@ -1819,38 +1924,40 @@ public boolean dataDefinitionIgnoredInTransactions() { /** * Retrieves a description of the stored procedures available in the given catalog. Only procedure - * descriptions matching the schema and procedure name criteria are returned. They are ordered - * by - * PROCEDURE_CAT, - * PROCEDURE_SCHEM, PROCEDURE_NAME and SPECIFIC_ NAME. - * - *

Each procedure description has the the following columns:

- * - *
  1. PROCEDURE_CAT - * String {@code =>} procedure catalog (may be - * null)
  2. PROCEDURE_SCHEM String {@code =>} procedure schema (may be - * null)
  3. PROCEDURE_NAME String - * {@code =>} procedure name
  4. reserved for future use
  5. reserved for future use
  6. - * reserved for future use
  7. REMARKS String {@code =>} explanatory comment on the - * procedure
  8. PROCEDURE_TYPE short {@code =>} kind of procedure:
    • - * procedureResultUnknown - Cannot determine if a return value will be returned
    • - * procedureNoResult - Does not return a return value
    • procedureReturnsResult - Returns a - * return value
  9. SPECIFIC_NAME String {@code =>} The name which uniquely - * identifies this procedure within its schema. + * descriptions matching the schema and procedure name criteria are returned. They are ordered by + * PROCEDURE_CAT, PROCEDURE_SCHEM, PROCEDURE_NAME and + * SPECIFIC_ NAME. + * + *

    Each procedure description has the the following columns: + * + *

      + *
    1. PROCEDURE_CAT String {@code =>} procedure catalog (may be null) + *
    2. PROCEDURE_SCHEM String {@code =>} procedure schema (may be null) + *
    3. PROCEDURE_NAME String {@code =>} procedure name + *
    4. reserved for future use + *
    5. reserved for future use + *
    6. reserved for future use + *
    7. REMARKS String {@code =>} explanatory comment on the procedure + *
    8. PROCEDURE_TYPE short {@code =>} kind of procedure: + *
        + *
      • procedureResultUnknown - Cannot determine if a return value will be returned + *
      • procedureNoResult - Does not return a return value + *
      • procedureReturnsResult - Returns a return value + *
      + *
    9. SPECIFIC_NAME String {@code =>} The name which uniquely identifies this procedure + * within its schema. *
    - * A user may not have permissions to execute any of the procedures that are returned by - * getProcedures - * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used - * to narrow the search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored - * in the database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search + *

    A user may not have permissions to execute any of the procedures that are returned by + * getProcedures

    + * + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search * @param procedureNamePattern a procedure name pattern; must match the procedure name as it is - * stored in the database + * stored in the database * @return ResultSet - each row is a procedure description * @throws SQLException if a database access error occurs * @see #getSearchStringEscape @@ -1862,9 +1969,12 @@ public ResultSet getProcedures(String catalog, String schemaPattern, String proc "SELECT ROUTINE_SCHEMA PROCEDURE_CAT,NULL PROCEDURE_SCHEM, ROUTINE_NAME PROCEDURE_NAME," + " NULL RESERVED1, NULL RESERVED2, NULL RESERVED3," + " CASE ROUTINE_TYPE " - + " WHEN 'FUNCTION' THEN " + procedureReturnsResult - + " WHEN 'PROCEDURE' THEN " + procedureNoResult - + " ELSE " + procedureResultUnknown + + " WHEN 'FUNCTION' THEN " + + procedureReturnsResult + + " WHEN 'PROCEDURE' THEN " + + procedureNoResult + + " ELSE " + + procedureResultUnknown + " END PROCEDURE_TYPE," + " ROUTINE_COMMENT REMARKS, SPECIFIC_NAME " + " FROM INFORMATION_SCHEMA.ROUTINES " @@ -1884,81 +1994,99 @@ private boolean haveInformationSchemaParameters() { /** * Retrieves a description of the given catalog's stored procedure parameter and result columns. * - *

    Only descriptions matching the schema, procedure and parameter name criteria are returned. + *

    Only descriptions matching the schema, procedure and parameter name criteria are returned. * They are ordered by PROCEDURE_CAT, PROCEDURE_SCHEM, PROCEDURE_NAME and SPECIFIC_NAME. Within * this, the return value, if any, is first. Next are the parameter descriptions in call order. - * The column descriptions follow in column number order.

    + * The column descriptions follow in column number order. * - *

    Each row in the ResultSet is a parameter description or column description - * with the following fields:

    + *

    Each row in the ResultSet is a parameter description or column description with + * the following fields: * *

      - *
    1. PROCEDURE_CAT String {@code =>} procedure catalog (may be null) - *
    2. PROCEDURE_SCHEM String {@code =>} procedure - * schema (may be null)
    3. PROCEDURE_NAME String {@code =>} procedure name - *
    4. COLUMN_NAME String {@code =>} column/parameter name
    5. COLUMN_TYPE Short - * {@code =>} kind of column/parameter:
      • procedureColumnUnknown - nobody knows
      • - * procedureColumnIn - IN parameter
      • procedureColumnInOut - INOUT parameter
      • - * procedureColumnOut - OUT parameter
      • procedureColumnReturn - procedure return value
      • - * procedureColumnResult - result column in ResultSet
    6. DATA_TYPE int - * {@code =>} SQL type from java.sql.Types
    7. TYPE_NAME String {@code =>} SQL type name, - * for a UDT type the type name is fully qualified - *
    8. PRECISION int {@code =>} precision
    9. LENGTH int {@code =>} length in bytes - * of data
    10. SCALE short {@code =>} scale - null is returned for data types where SCALE - * is not applicable.
    11. RADIX short {@code =>} radix
    12. NULLABLE short {@code =>} - * can it contain NULL.
      • procedureNoNulls - does not allow NULL values
      • - * procedureNullable - allows NULL values
      • procedureNullableUnknown - nullability unknown - *
    13. REMARKS String {@code =>} comment describing parameter/column - *
    14. COLUMN_DEF String {@code =>} default value for the column, which should be - * interpreted as a string when the value is enclosed in single quotes (may be null) - *
      • The string NULL (not enclosed in quotes) - if NULL was specified as the default - * value - *
      • TRUNCATE (not enclosed in quotes) - if the specified default value cannot be - * represented without truncation
      • NULL - if a default value was not specified
      - *
    15. SQL_DATA_TYPE int {@code =>} reserved for future use - *
    16. SQL_DATETIME_SUB int {@code =>} reserved for future use - *
    17. CHAR_OCTET_LENGTH int {@code =>} the maximum length of binary and character based - * columns. For any other datatype the returned value is a NULL
    18. ORDINAL_POSITION int - * {@code =>} the ordinal position, starting from 1, for the input and output parameters for a - * procedure. A value of 0 is returned if this row describes the procedure's return value. For - * result set columns, it is the ordinal position of the column in the result set starting from 1. - * If there are multiple result sets, the column ordinal positions are implementation defined. - *
    19. IS_NULLABLE String {@code =>} ISO rules are used to determine the nullability for - * a column.
      • YES --- if the column can include NULLs
      • NO --- if the - * column cannot include NULLs
      • empty string --- if the nullability for the column is - * unknown - *
      - *
    20. SPECIFIC_NAME String {@code =>} the name which uniquely identifies this procedure - * within its schema.
    - * - *

    Note: Some databases may not return the column descriptions for a procedure.

    + *
  10. PROCEDURE_CAT String {@code =>} procedure catalog (may be null) + *
  11. PROCEDURE_SCHEM String {@code =>} procedure schema (may be null) + *
  12. PROCEDURE_NAME String {@code =>} procedure name + *
  13. COLUMN_NAME String {@code =>} column/parameter name + *
  14. COLUMN_TYPE Short {@code =>} kind of column/parameter: + *
      + *
    • procedureColumnUnknown - nobody knows + *
    • procedureColumnIn - IN parameter + *
    • procedureColumnInOut - INOUT parameter + *
    • procedureColumnOut - OUT parameter + *
    • procedureColumnReturn - procedure return value + *
    • procedureColumnResult - result column in ResultSet + *
    + *
  15. DATA_TYPE int {@code =>} SQL type from java.sql.Types + *
  16. TYPE_NAME String {@code =>} SQL type name, for a UDT type the type name is fully + * qualified + *
  17. PRECISION int {@code =>} precision + *
  18. LENGTH int {@code =>} length in bytes of data + *
  19. SCALE short {@code =>} scale - null is returned for data types where SCALE is not + * applicable. + *
  20. RADIX short {@code =>} radix + *
  21. NULLABLE short {@code =>} can it contain NULL. + *
      + *
    • procedureNoNulls - does not allow NULL values + *
    • procedureNullable - allows NULL values + *
    • procedureNullableUnknown - nullability unknown + *
    + *
  22. REMARKS String {@code =>} comment describing parameter/column + *
  23. COLUMN_DEF String {@code =>} default value for the column, which should be + * interpreted as a string when the value is enclosed in single quotes (may be null + * ) + *
      + *
    • The string NULL (not enclosed in quotes) - if NULL was specified as the default + * value + *
    • TRUNCATE (not enclosed in quotes) - if the specified default value cannot be + * represented without truncation + *
    • NULL - if a default value was not specified + *
    + *
  24. SQL_DATA_TYPE int {@code =>} reserved for future use + *
  25. SQL_DATETIME_SUB int {@code =>} reserved for future use + *
  26. CHAR_OCTET_LENGTH int {@code =>} the maximum length of binary and character based + * columns. For any other datatype the returned value is a NULL + *
  27. ORDINAL_POSITION int {@code =>} the ordinal position, starting from 1, for the + * input and output parameters for a procedure. A value of 0 is returned if this row + * describes the procedure's return value. For result set columns, it is the ordinal + * position of the column in the result set starting from 1. If there are multiple result + * sets, the column ordinal positions are implementation defined. + *
  28. IS_NULLABLE String {@code =>} ISO rules are used to determine the nullability for + * a column. + *
      + *
    • YES --- if the column can include NULLs + *
    • NO --- if the column cannot include NULLs + *
    • empty string --- if the nullability for the column is unknown + *
    + *
  29. SPECIFIC_NAME String {@code =>} the name which uniquely identifies this procedure + * within its schema. + *
+ * + *

Note: Some databases may not return the column descriptions for a procedure. * *

The PRECISION column represents the specified column size for the given column. For numeric - * data, this is the maximum precision. For character data, this is the length in characters. For + * data, this is the maximum precision. For character data, this is the length in characters. For * datetime datatypes, this is the length in characters of the String representation (assuming the * maximum allowed precision of the fractional seconds component). For binary data, this is the - * length in bytes. For the ROWID datatype, this is the length in bytes. Null is returned for - * data types where the column size is not applicable.

- * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used - * to narrow the search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored - * in the database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search + * length in bytes. For the ROWID datatype, this is the length in bytes. Null is returned for data + * types where the column size is not applicable. + * + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search * @param procedureNamePattern a procedure name pattern; must match the procedure name as it is - * stored in the database - * @param columnNamePattern a column name pattern; must match the column name as it is stored - * in the database + * stored in the database + * @param columnNamePattern a column name pattern; must match the column name as it is stored in + * the database * @return ResultSet - each row describes a stored procedure parameter or column * @throws SQLException if a database access error occurs * @see #getSearchStringEscape */ - public ResultSet getProcedureColumns(String catalog, String schemaPattern, - String procedureNamePattern, - String columnNamePattern) throws SQLException { + public ResultSet getProcedureColumns( + String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) + throws SQLException { String sql; if (haveInformationSchemaParameters()) { @@ -1969,59 +2097,67 @@ public ResultSet getProcedureColumns(String catalog, String schemaPattern, "SELECT SPECIFIC_SCHEMA PROCEDURE_CAT, NULL PROCEDURE_SCHEM, SPECIFIC_NAME PROCEDURE_NAME," + " PARAMETER_NAME COLUMN_NAME, " + " CASE PARAMETER_MODE " - + " WHEN 'IN' THEN " + procedureColumnIn - + " WHEN 'OUT' THEN " + procedureColumnOut - + " WHEN 'INOUT' THEN " + procedureColumnInOut - + " ELSE IF(PARAMETER_MODE IS NULL," + procedureColumnReturn + "," - + procedureColumnUnknown + ")" + + " WHEN 'IN' THEN " + + procedureColumnIn + + " WHEN 'OUT' THEN " + + procedureColumnOut + + " WHEN 'INOUT' THEN " + + procedureColumnInOut + + " ELSE IF(PARAMETER_MODE IS NULL," + + procedureColumnReturn + + "," + + procedureColumnUnknown + + ")" + " END COLUMN_TYPE," - + dataTypeClause("DTD_IDENTIFIER") + " DATA_TYPE," + + dataTypeClause("DTD_IDENTIFIER") + + " DATA_TYPE," + "DATA_TYPE TYPE_NAME," + " CASE DATA_TYPE" + " WHEN 'time' THEN " + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 10, CAST(11 + DATETIME_PRECISION as signed integer))" - : "10") + ? "IF(DATETIME_PRECISION = 0, 10, CAST(11 + DATETIME_PRECISION as signed integer))" + : "10") + " WHEN 'date' THEN 10" + " WHEN 'datetime' THEN " + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" - : "19") + ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" + : "19") + " WHEN 'timestamp' THEN " + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" - : "19") + ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" + : "19") + " ELSE " + " IF(NUMERIC_PRECISION IS NULL, LEAST(CHARACTER_MAXIMUM_LENGTH," - + Integer.MAX_VALUE + "), NUMERIC_PRECISION) " + + Integer.MAX_VALUE + + "), NUMERIC_PRECISION) " + " END `PRECISION`," - + " CASE DATA_TYPE" + " WHEN 'time' THEN " + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 10, CAST(11 + DATETIME_PRECISION as signed integer))" - : "10") + ? "IF(DATETIME_PRECISION = 0, 10, CAST(11 + DATETIME_PRECISION as signed integer))" + : "10") + " WHEN 'date' THEN 10" + " WHEN 'datetime' THEN " + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" - : "19") + ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" + : "19") + " WHEN 'timestamp' THEN " + (datePrecisionColumnExist - ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" - : "19") + ? "IF(DATETIME_PRECISION = 0, 19, CAST(20 + DATETIME_PRECISION as signed integer))" + : "19") + " ELSE " + " IF(NUMERIC_PRECISION IS NULL, LEAST(CHARACTER_MAXIMUM_LENGTH," - + Integer.MAX_VALUE + "), NUMERIC_PRECISION) " + + Integer.MAX_VALUE + + "), NUMERIC_PRECISION) " + " END `LENGTH`," - - + (datePrecisionColumnExist ? " CASE DATA_TYPE" - + " WHEN 'time' THEN CAST(DATETIME_PRECISION as signed integer)" - + " WHEN 'datetime' THEN CAST(DATETIME_PRECISION as signed integer)" - + " WHEN 'timestamp' THEN CAST(DATETIME_PRECISION as signed integer)" - + " ELSE NUMERIC_SCALE " - + " END `SCALE`," : " NUMERIC_SCALE `SCALE`,") - + + (datePrecisionColumnExist + ? " CASE DATA_TYPE" + + " WHEN 'time' THEN CAST(DATETIME_PRECISION as signed integer)" + + " WHEN 'datetime' THEN CAST(DATETIME_PRECISION as signed integer)" + + " WHEN 'timestamp' THEN CAST(DATETIME_PRECISION as signed integer)" + + " ELSE NUMERIC_SCALE " + + " END `SCALE`," + : " NUMERIC_SCALE `SCALE`,") + "10 RADIX," + procedureNullableUnknown + " NULLABLE,NULL REMARKS,NULL COLUMN_DEF,0 SQL_DATA_TYPE,0 SQL_DATETIME_SUB," @@ -2029,8 +2165,10 @@ public ResultSet getProcedureColumns(String catalog, String schemaPattern, + " FROM INFORMATION_SCHEMA.PARAMETERS " + " WHERE " + catalogCond("SPECIFIC_SCHEMA", catalog) - + " AND " + patternCond("SPECIFIC_NAME", procedureNamePattern) - + " AND " + patternCond("PARAMETER_NAME", columnNamePattern) + + " AND " + + patternCond("SPECIFIC_NAME", procedureNamePattern) + + " AND " + + patternCond("PARAMETER_NAME", columnNamePattern) + " /* AND ROUTINE_TYPE='PROCEDURE' */ " + " ORDER BY SPECIFIC_SCHEMA, SPECIFIC_NAME, ORDINAL_POSITION"; } else { @@ -2063,74 +2201,90 @@ public ResultSet getProcedureColumns(String catalog, String schemaPattern, * Retrieves a description of the given catalog's system or user function parameters and return * type. * - *

Only descriptions matching the schema, function and parameter name criteria are returned. - * They are ordered by FUNCTION_CAT, - * FUNCTION_SCHEM, FUNCTION_NAME and SPECIFIC_ NAME. - * Within this, the return value, if any, is first. Next are the parameter descriptions in call - * order. The column descriptions follow in column number order.

- * - *

Each row in the ResultSet is a parameter description, column description or - * return type description with the following fields:

- * - *
  1. FUNCTION_CAT String {@code =>} function catalog (may be null) - *
  2. FUNCTION_SCHEM String {@code =>} function - * schema (may be null)
  3. FUNCTION_NAME String {@code =>} function name. - * This is the name used to invoke the function - *
  4. COLUMN_NAME String {@code =>} column/parameter name
  5. COLUMN_TYPE Short - * {@code =>} kind of column/parameter:
    • functionColumnUnknown - nobody knows
    • - * functionColumnIn - IN parameter
    • functionColumnInOut - INOUT parameter
    • - * functionColumnOut - OUT parameter
    • functionColumnReturn - function return value
    • - * functionColumnResult - Indicates that the parameter or column is a column in the - * ResultSet
  6. DATA_TYPE int {@code =>} SQL type from java.sql.Types - *
  7. TYPE_NAME String {@code =>} SQL type name, for a UDT type the type name is fully - * qualified
  8. PRECISION int {@code =>} precision - *
  9. LENGTH int {@code =>} length in bytes of data
  10. SCALE short {@code =>} - * scale - null is returned for data types where SCALE is not applicable. - *
  11. RADIX short {@code =>} radix
  12. NULLABLE short {@code =>} can it contain - * NULL.
    • functionNoNulls - does not allow NULL values
    • functionNullable - allows - * NULL values
    • functionNullableUnknown - nullability unknown
  13. REMARKS String - * {@code =>} comment describing column/parameter
  14. CHAR_OCTET_LENGTH int {@code =>} the - * maximum length of binary and character based parameters or columns. For any other datatype the - * returned value is a NULL - *
  15. ORDINAL_POSITION int {@code =>} the ordinal position, starting from 1, for the - * input and output parameters. A value of 0 is returned if this row describes the function's - * return value. For result set columns, it is the ordinal position of the column in the result - * set starting from 1.
  16. IS_NULLABLE String {@code =>} ISO rules are used to determine - * the nullability for a parameter or column.
    • YES --- if the parameter or - * column can include NULLs
    • NO --- if the parameter or column cannot include - * NULLs
    • empty string --- if the nullability for the parameter or column is unknown
    - *
  17. SPECIFIC_NAME String {@code =>} the name which uniquely identifies this function - * within its schema. This is a user specified, or DBMS generated, name that may be different - * then the FUNCTION_NAME for example with overload functions
- * - *

The PRECISION column represents the specified column size for the given parameter or - * column. For numeric data, this is the maximum precision. For character data, this is the - * length in characters. For datetime datatypes, this is the length in characters of the String + *

Only descriptions matching the schema, function and parameter name criteria are returned. + * They are ordered by FUNCTION_CAT, FUNCTION_SCHEM, FUNCTION_NAME + * and SPECIFIC_ NAME. Within this, the return value, if any, is first. Next + * are the parameter descriptions in call order. The column descriptions follow in column number + * order. + * + *

Each row in the ResultSet is a parameter description, column description or + * return type description with the following fields: + * + *

    + *
  1. FUNCTION_CAT String {@code =>} function catalog (may be null) + *
  2. FUNCTION_SCHEM String {@code =>} function schema (may be null) + *
  3. FUNCTION_NAME String {@code =>} function name. This is the name used to invoke the + * function + *
  4. COLUMN_NAME String {@code =>} column/parameter name + *
  5. COLUMN_TYPE Short {@code =>} kind of column/parameter: + *
      + *
    • functionColumnUnknown - nobody knows + *
    • functionColumnIn - IN parameter + *
    • functionColumnInOut - INOUT parameter + *
    • functionColumnOut - OUT parameter + *
    • functionColumnReturn - function return value + *
    • functionColumnResult - Indicates that the parameter or column is a column in the + * ResultSet + *
    + *
  6. DATA_TYPE int {@code =>} SQL type from java.sql.Types + *
  7. TYPE_NAME String {@code =>} SQL type name, for a UDT type the type name is fully + * qualified + *
  8. PRECISION int {@code =>} precision + *
  9. LENGTH int {@code =>} length in bytes of data + *
  10. SCALE short {@code =>} scale - null is returned for data types where SCALE is not + * applicable. + *
  11. RADIX short {@code =>} radix + *
  12. NULLABLE short {@code =>} can it contain NULL. + *
      + *
    • functionNoNulls - does not allow NULL values + *
    • functionNullable - allows NULL values + *
    • functionNullableUnknown - nullability unknown + *
    + *
  13. REMARKS String {@code =>} comment describing column/parameter + *
  14. CHAR_OCTET_LENGTH int {@code =>} the maximum length of binary and character based + * parameters or columns. For any other datatype the returned value is a NULL + *
  15. ORDINAL_POSITION int {@code =>} the ordinal position, starting from 1, for the + * input and output parameters. A value of 0 is returned if this row describes the + * function's return value. For result set columns, it is the ordinal position of the column + * in the result set starting from 1. + *
  16. IS_NULLABLE String {@code =>} ISO rules are used to determine the nullability for + * a parameter or column. + *
      + *
    • YES --- if the parameter or column can include NULLs + *
    • NO --- if the parameter or column cannot include NULLs + *
    • empty string --- if the nullability for the parameter or column is unknown + *
    + *
  17. SPECIFIC_NAME String {@code =>} the name which uniquely identifies this function + * within its schema. This is a user specified, or DBMS generated, name that may be + * different then the FUNCTION_NAME for example with overload functions + *
+ * + *

The PRECISION column represents the specified column size for the given parameter or column. + * For numeric data, this is the maximum precision. For character data, this is the length in + * characters. For datetime datatypes, this is the length in characters of the String * representation (assuming the maximum allowed precision of the fractional seconds component). * For binary data, this is the length in bytes. For the ROWID datatype, this is the length in - * bytes. Null is returned for data types where the column size is not applicable.

- * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used to - * narrow the search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored in - * the database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search + * bytes. Null is returned for data types where the column size is not applicable. + * + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search * @param functionNamePattern a procedure name pattern; must match the function name as it is - * stored in the database - * @param columnNamePattern a parameter name pattern; must match the parameter or column name as - * it is stored in the database - * @return ResultSet - each row describes a user function parameter, column or - * return type + * stored in the database + * @param columnNamePattern a parameter name pattern; must match the parameter or column name as + * it is stored in the database + * @return ResultSet - each row describes a user function parameter, column or return + * type * @throws SQLException if a database access error occurs * @see #getSearchStringEscape * @since 1.6 */ - public ResultSet getFunctionColumns(String catalog, String schemaPattern, - String functionNamePattern, - String columnNamePattern) throws SQLException { + public ResultSet getFunctionColumns( + String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) + throws SQLException { String sql; if (haveInformationSchemaParameters()) { @@ -2139,20 +2293,28 @@ public ResultSet getFunctionColumns(String catalog, String schemaPattern, "SELECT SPECIFIC_SCHEMA `FUNCTION_CAT`, NULL `FUNCTION_SCHEM`, SPECIFIC_NAME FUNCTION_NAME," + " PARAMETER_NAME COLUMN_NAME, " + " CASE PARAMETER_MODE " - + " WHEN 'IN' THEN " + functionColumnIn - + " WHEN 'OUT' THEN " + functionColumnOut - + " WHEN 'INOUT' THEN " + functionColumnInOut - + " ELSE " + functionReturn + + " WHEN 'IN' THEN " + + functionColumnIn + + " WHEN 'OUT' THEN " + + functionColumnOut + + " WHEN 'INOUT' THEN " + + functionColumnInOut + + " ELSE " + + functionReturn + " END COLUMN_TYPE," - + dataTypeClause("DTD_IDENTIFIER") + " DATA_TYPE," + + dataTypeClause("DTD_IDENTIFIER") + + " DATA_TYPE," + "DATA_TYPE TYPE_NAME,NUMERIC_PRECISION `PRECISION`,CHARACTER_MAXIMUM_LENGTH LENGTH,NUMERIC_SCALE SCALE,10 RADIX," - + procedureNullableUnknown + " NULLABLE,NULL REMARKS," + + procedureNullableUnknown + + " NULLABLE,NULL REMARKS," + "CHARACTER_OCTET_LENGTH CHAR_OCTET_LENGTH ,ORDINAL_POSITION, '' IS_NULLABLE, SPECIFIC_NAME " + " FROM INFORMATION_SCHEMA.PARAMETERS " + " WHERE " + catalogCond("SPECIFIC_SCHEMA", catalog) - + " AND " + patternCond("SPECIFIC_NAME", functionNamePattern) - + " AND " + patternCond("PARAMETER_NAME", columnNamePattern) + + " AND " + + patternCond("SPECIFIC_NAME", functionNamePattern) + + " AND " + + patternCond("PARAMETER_NAME", columnNamePattern) + " AND ROUTINE_TYPE='FUNCTION'" + " ORDER BY FUNCTION_CAT, SPECIFIC_NAME, ORDINAL_POSITION"; } else { @@ -2173,8 +2335,7 @@ public ResultSet getFunctionColumns(String catalog, String schemaPattern, } public ResultSet getSchemas() throws SQLException { - return executeQuery( - "SELECT '' TABLE_SCHEM, '' TABLE_catalog FROM DUAL WHERE 1=0"); + return executeQuery("SELECT '' TABLE_SCHEM, '' TABLE_catalog FROM DUAL WHERE 1=0"); } public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { @@ -2182,8 +2343,7 @@ public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLExce } public ResultSet getCatalogs() throws SQLException { - return executeQuery( - "SELECT SCHEMA_NAME TABLE_CAT FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY 1"); + return executeQuery("SELECT SCHEMA_NAME TABLE_CAT FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY 1"); } public ResultSet getTableTypes() throws SQLException { @@ -2194,40 +2354,39 @@ public ResultSet getTableTypes() throws SQLException { /** * Retrieves a description of the access rights for a table's columns. * - *

Only privileges matching the column name criteria are returned. They are ordered by - * COLUMN_NAME and PRIVILEGE.

- * - *

Each privilege description has the following columns:

- * - *
  1. TABLE_CAT String - * {@code =>} table catalog (may be null) - *
  2. TABLE_SCHEM String {@code =>} table schema (may be null) - *
  3. TABLE_NAME String {@code =>} table name - *
  4. COLUMN_NAME String {@code =>} column name
  5. GRANTOR String {@code =>} - * grantor of access (may be null) - *
  6. GRANTEE String {@code =>} grantee of access
  7. PRIVILEGE String {@code =>} - * name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String {@code - * =>} "YES" if grantee is permitted to grant to others; "NO" if not; null if - * unknown + *

    Only privileges matching the column name criteria are returned. They are ordered by + * COLUMN_NAME and PRIVILEGE. + * + *

    Each privilege description has the following columns: + * + *

      + *
    1. TABLE_CAT String {@code =>} table catalog (may be null) + *
    2. TABLE_SCHEM String {@code =>} table schema (may be null) + *
    3. TABLE_NAME String {@code =>} table name + *
    4. COLUMN_NAME String {@code =>} column name + *
    5. GRANTOR String {@code =>} grantor of access (may be null) + *
    6. GRANTEE String {@code =>} grantee of access + *
    7. PRIVILEGE String {@code =>} name of access (SELECT, INSERT, UPDATE, REFRENCES, + * ...) + *
    8. IS_GRANTABLE String {@code =>} "YES" if grantee is permitted to grant to others; + * "NO" if not; null if unknown *
    * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used to - * narrow the search - * @param schema a schema name; must match the schema name as it is stored in the - * database; "" retrieves those without a schema; null means - * that the schema name should not be used to narrow the search - * @param table a table name; must match the table name as it is stored in the - * database + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schema a schema name; must match the schema name as it is stored in the database; "" + * retrieves those without a schema; null means that the schema name should not + * be used to narrow the search + * @param table a table name; must match the table name as it is stored in the database * @param columnNamePattern a column name pattern; must match the column name as it is stored in - * the database + * the database * @return ResultSet - each row is a column privilege description * @throws SQLException if a database access error occurs * @see #getSearchStringEscape */ - public ResultSet getColumnPrivileges(String catalog, String schema, String table, - String columnNamePattern) throws SQLException { + public ResultSet getColumnPrivileges( + String catalog, String schema, String table, String columnNamePattern) throws SQLException { if (table == null) { throw new SQLException("'table' parameter must not be null"); @@ -2238,7 +2397,8 @@ public ResultSet getColumnPrivileges(String catalog, String schema, String table + " INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE " + catalogCond("TABLE_SCHEMA", catalog) + " AND " - + " TABLE_NAME = " + escapeQuote(table) + + " TABLE_NAME = " + + escapeQuote(table) + " AND " + patternCond("COLUMN_NAME", columnNamePattern) + " ORDER BY COLUMN_NAME, PRIVILEGE_TYPE"; @@ -2252,32 +2412,32 @@ public ResultSet getColumnPrivileges(String catalog, String schema, String table * this privilege applies to all columns (this may be true for some systems but is not true for * all.) * - *

    Only privileges matching the schema and table name criteria are returned. They are ordered - * by TABLE_CAT, - * TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

    - * - *

    Each privilege description has the following columns:

    - * - *
    1. TABLE_CAT String - * {@code =>} table catalog (may be null) - *
    2. TABLE_SCHEM String {@code =>} table schema (may be null) - *
    3. TABLE_NAME String {@code =>} table name - *
    4. GRANTOR String {@code =>} grantor of access (may be null) - *
    5. GRANTEE String {@code =>} grantee of access - *
    6. PRIVILEGE String {@code =>} name of access (SELECT, INSERT, UPDATE, REFRENCES, ...) - *
    7. IS_GRANTABLE String {@code =>} "YES" - * if grantee is permitted to grant to others; "NO" if not; null if unknown
    - * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used to - * narrow the search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored in - * the database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search + *

    Only privileges matching the schema and table name criteria are returned. They are ordered + * by TABLE_CAT, TABLE_SCHEM, TABLE_NAME, and + * PRIVILEGE. + * + *

    Each privilege description has the following columns: + * + *

      + *
    1. TABLE_CAT String {@code =>} table catalog (may be null) + *
    2. TABLE_SCHEM String {@code =>} table schema (may be null) + *
    3. TABLE_NAME String {@code =>} table name + *
    4. GRANTOR String {@code =>} grantor of access (may be null) + *
    5. GRANTEE String {@code =>} grantee of access + *
    6. PRIVILEGE String {@code =>} name of access (SELECT, INSERT, UPDATE, REFRENCES, + * ...) + *
    7. IS_GRANTABLE String {@code =>} "YES" if grantee is permitted to grant to others; + * "NO" if not; null if unknown + *
    + * + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search * @param tableNamePattern a table name pattern; must match the table name as it is stored in the - * database + * database * @return ResultSet - each row is a table privilege description * @throws SQLException if a database access error occurs * @see #getSearchStringEscape @@ -2298,36 +2458,41 @@ public ResultSet getTablePrivileges(String catalog, String schemaPattern, String /** * Retrieves a description of a table's columns that are automatically updated when any value in a - * row is updated. They are unordered. - * - *

    Each column description has the following columns:

    - * - *
    1. SCOPE short {@code =>} - * is not used
    2. COLUMN_NAME String {@code =>} column name
    3. DATA_TYPE int - * {@code =>} SQL data type from - * java.sql.Types
    4. TYPE_NAME String {@code =>} Data source-dependent type - * name
    5. COLUMN_SIZE int {@code =>} precision
    6. BUFFER_LENGTH int {@code =>} - * length of column value in bytes
    7. DECIMAL_DIGITS short {@code =>} scale - Null is - * returned for data types where DECIMAL_DIGITS is not applicable. - *
    8. PSEUDO_COLUMN short {@code =>} whether this is pseudo column like an Oracle ROWID - *
      • versionColumnUnknown - may or may not be - * pseudo column
      • versionColumnNotPseudo - is NOT a pseudo column
      • versionColumnPseudo - - * is a pseudo column
    + * row is updated. They are unordered. + * + *

    Each column description has the following columns: + * + *

      + *
    1. SCOPE short {@code =>} is not used + *
    2. COLUMN_NAME String {@code =>} column name + *
    3. DATA_TYPE int {@code =>} SQL data type from java.sql.Types + *
    4. TYPE_NAME String {@code =>} Data source-dependent type name + *
    5. COLUMN_SIZE int {@code =>} precision + *
    6. BUFFER_LENGTH int {@code =>} length of column value in bytes + *
    7. DECIMAL_DIGITS short {@code =>} scale - Null is returned for data types where + * DECIMAL_DIGITS is not applicable. + *
    8. PSEUDO_COLUMN short {@code =>} whether this is pseudo column like an Oracle ROWID + *
        + *
      • versionColumnUnknown - may or may not be pseudo column + *
      • versionColumnNotPseudo - is NOT a pseudo column + *
      • versionColumnPseudo - is a pseudo column + *
      + *
    * *

    The COLUMN_SIZE column represents the specified column size for the given column. For - * numeric data, this is the maximum precision. For character data, this is the length in + * numeric data, this is the maximum precision. For character data, this is the length in * characters. For datetime datatypes, this is the length in characters of the String * representation (assuming the maximum allowed precision of the fractional seconds component). - * For binary data, this is the length in bytes. For the ROWID datatype, this is the length in - * bytes. Null is returned for data types where the column size is not applicable.

    + * For binary data, this is the length in bytes. For the ROWID datatype, this is the length in + * bytes. Null is returned for data types where the column size is not applicable. * * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" - * retrieves those without a catalog;null means that the catalog name - * should not be used to narrow the search - * @param schema a schema name; must match the schema name as it is stored in the database; "" - * retrieves those without a schema; null means that the schema name - * should not be used to narrow the search - * @param table a table name; must match the table name as it is stored in the database + * retrieves those without a catalog;null means that the catalog name should not + * be used to narrow the search + * @param schema a schema name; must match the schema name as it is stored in the database; "" + * retrieves those without a schema; null means that the schema name should not + * be used to narrow the search + * @param table a table name; must match the table name as it is stored in the database * @return a ResultSet object in which each row is a column description * @throws SQLException if a database access error occurs */ @@ -2343,67 +2508,87 @@ public ResultSet getVersionColumns(String catalog, String schema, String table) /** * Retrieves a description of the foreign key columns in the given foreign key table that - * reference the primary key or the columns representing a unique constraint of the parent table + * reference the primary key or the columns representing a unique constraint of the parent table * (could be the same or a different table). The number of columns returned from the parent table - * must match the number of columns that make up the foreign key. They are ordered by - * FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ. - * - *

    Each foreign key column description has the following columns:

    - * - *
    1. PKTABLE_CAT - * String {@code =>} parent key table catalog (may be null)
    2. PKTABLE_SCHEM - * String {@code =>} parent key table schema (may be null)
    3. PKTABLE_NAME - * String {@code =>} parent key table name - *
    4. PKCOLUMN_NAME String {@code =>} parent key column name
    5. FKTABLE_CAT - * String {@code =>} foreign key table catalog (may be null) being exported (may be - * null)
    6. FKTABLE_SCHEM String {@code =>} foreign key table schema (may be - * null) being exported (may be null)
    7. FKTABLE_NAME String - * {@code =>} foreign key table name being exported
    8. FKCOLUMN_NAME String {@code =>} - * foreign key column name being exported
    9. KEY_SEQ short {@code =>} sequence number - * within foreign key( a value of 1 represents the first column of the foreign key, a value of 2 - * would represent the second column within the foreign key).
    10. UPDATE_RULE short {@code - * =>} What happens to foreign key when parent key is updated:
      • importedNoAction - do not - * allow update of parent key if it has been imported
      • importedKeyCascade - change imported - * key to agree with parent key update
      • importedKeySetNull - change imported key to - * NULL if its parent key has been updated
      • importedKeySetDefault - change - * imported key to default values if its parent key has been updated
      • importedKeyRestrict - - * same as importedKeyNoAction (for ODBC 2.x compatibility)
    11. DELETE_RULE short - * {@code =>} What happens to the foreign key when parent key is deleted.
      • - * importedKeyNoAction - do not allow delete of parent key if it has been imported
      • - * importedKeyCascade - delete rows that import a deleted key - *
      • importedKeySetNull - change imported key to NULL if its primary key has been - * deleted
      • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) - *
      • importedKeySetDefault - change imported key to default if its parent key has been deleted - *
    12. FK_NAME String {@code =>} foreign key name (may be null) - *
    13. PK_NAME String {@code =>} parent key name - * (may be null)
    14. DEFERRABILITY short {@code =>} can the evaluation of - * foreign key constraints be deferred until commit - *
      • importedKeyInitiallyDeferred - see SQL92 for definition
      • - * importedKeyInitiallyImmediate - see SQL92 for definition
      • importedKeyNotDeferrable - see - * SQL92 for definition
    - * - * @param parentCatalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means drop catalog name from the selection criteria - * @param parentSchema a schema name; must match the schema name as it is stored in the - * database; "" retrieves those without a schema; - * null means drop schema name from the selection criteria - * @param parentTable the name of the table that exports the key; must match the table name as - * it is stored in the database + * must match the number of columns that make up the foreign key. They are ordered by FKTABLE_CAT, + * FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ. + * + *

    Each foreign key column description has the following columns: + * + *

      + *
    1. PKTABLE_CAT String {@code =>} parent key table catalog (may be null) + *
    2. PKTABLE_SCHEM String {@code =>} parent key table schema (may be null) + *
    3. PKTABLE_NAME String {@code =>} parent key table name + *
    4. PKCOLUMN_NAME String {@code =>} parent key column name + *
    5. FKTABLE_CAT String {@code =>} foreign key table catalog (may be null) + * being exported (may be null) + *
    6. FKTABLE_SCHEM String {@code =>} foreign key table schema (may be null + * ) being exported (may be null) + *
    7. FKTABLE_NAME String {@code =>} foreign key table name being exported + *
    8. FKCOLUMN_NAME String {@code =>} foreign key column name being exported + *
    9. KEY_SEQ short {@code =>} sequence number within foreign key( a value of 1 + * represents the first column of the foreign key, a value of 2 would represent the second + * column within the foreign key). + *
    10. UPDATE_RULE short {@code =>} What happens to foreign key when parent key is + * updated: + *
        + *
      • importedNoAction - do not allow update of parent key if it has been imported + *
      • importedKeyCascade - change imported key to agree with parent key update + *
      • importedKeySetNull - change imported key to NULL if its parent key has + * been updated + *
      • importedKeySetDefault - change imported key to default values if its parent key has + * been updated + *
      • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) + *
      + *
    11. DELETE_RULE short {@code =>} What happens to the foreign key when parent key is + * deleted. + *
        + *
      • importedKeyNoAction - do not allow delete of parent key if it has been imported + *
      • importedKeyCascade - delete rows that import a deleted key + *
      • importedKeySetNull - change imported key to NULL if its primary key + * has been deleted + *
      • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility) + *
      • importedKeySetDefault - change imported key to default if its parent key has been + * deleted + *
      + *
    12. FK_NAME String {@code =>} foreign key name (may be null) + *
    13. PK_NAME String {@code =>} parent key name (may be null) + *
    14. DEFERRABILITY short {@code =>} can the evaluation of foreign key constraints be + * deferred until commit + *
        + *
      • importedKeyInitiallyDeferred - see SQL92 for definition + *
      • importedKeyInitiallyImmediate - see SQL92 for definition + *
      • importedKeyNotDeferrable - see SQL92 for definition + *
      + *
    + * + * @param parentCatalog a catalog name; must match the catalog name as it is stored in the + * database; "" retrieves those without a catalog; null means drop catalog name + * from the selection criteria + * @param parentSchema a schema name; must match the schema name as it is stored in the database; + * "" retrieves those without a schema; null means drop schema name from the + * selection criteria + * @param parentTable the name of the table that exports the key; must match the table name as it + * is stored in the database * @param foreignCatalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means drop catalog name from the selection criteria - * @param foreignSchema a schema name; must match the schema name as it is stored in the - * database; "" retrieves those without a schema; - * null means drop schema name from the selection criteria - * @param foreignTable the name of the table that imports the key; must match the table name as - * it is stored in the database + * database; "" retrieves those without a catalog; null means drop catalog name + * from the selection criteria + * @param foreignSchema a schema name; must match the schema name as it is stored in the database; + * "" retrieves those without a schema; null means drop schema name from the + * selection criteria + * @param foreignTable the name of the table that imports the key; must match the table name as it + * is stored in the database * @return ResultSet - each row is a foreign key column description * @throws SQLException if a database access error occurs * @see #getImportedKeys */ - public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, - String foreignCatalog, String foreignSchema, String foreignTable) + public ResultSet getCrossReference( + String parentCatalog, + String parentSchema, + String parentTable, + String foreignCatalog, + String foreignSchema, + String foreignTable) throws SQLException { String sql = @@ -2426,7 +2611,8 @@ public ResultSet getCrossReference(String parentCatalog, String parentSchema, St + " END DELETE_RULE," + " RC.CONSTRAINT_NAME FK_NAME," + " NULL PK_NAME," - + importedKeyNotDeferrable + " DEFERRABILITY" + + importedKeyNotDeferrable + + " DEFERRABILITY" + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU" + " INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC" + " ON KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA" @@ -2436,9 +2622,11 @@ public ResultSet getCrossReference(String parentCatalog, String parentSchema, St + " AND " + catalogCond("KCU.TABLE_SCHEMA", foreignCatalog) + " AND " - + " KCU.REFERENCED_TABLE_NAME = " + escapeQuote(parentTable) + + " KCU.REFERENCED_TABLE_NAME = " + + escapeQuote(parentTable) + " AND " - + " KCU.TABLE_NAME = " + escapeQuote(foreignTable) + + " KCU.TABLE_NAME = " + + escapeQuote(foreignTable) + " ORDER BY FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, KEY_SEQ"; return executeQuery(sql); @@ -2448,245 +2636,773 @@ public ResultSet getCrossReference(String parentCatalog, String parentSchema, St * Retrieves a description of all the data types supported by this database. They are ordered by * DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type. * - *

    If the database supports SQL distinct types, then getTypeInfo() will return a single row + *

    If the database supports SQL distinct types, then getTypeInfo() will return a single row * with a TYPE_NAME of DISTINCT and a DATA_TYPE of Types.DISTINCT. If the database supports SQL * structured types, then getTypeInfo() will return a single row with a TYPE_NAME of STRUCT and a - * DATA_TYPE of Types.STRUCT.

    + * DATA_TYPE of Types.STRUCT. * - *

    If SQL distinct or structured types are supported, then information on the individual types - * may be obtained from the getUDTs() method.

    + *

    If SQL distinct or structured types are supported, then information on the individual types + * may be obtained from the getUDTs() method. * - *

    Each type description has the following columns:

    + *

    Each type description has the following columns: * *

      - *
    1. TYPE_NAME String {@code =>} Type name - *
    2. DATA_TYPE int {@code =>} - * SQL data type from java.sql.Types - *
    3. PRECISION int {@code =>} maximum precision - *
    4. LITERAL_PREFIX String {@code =>} prefix used to quote a literal (may be - * null) - *
    5. LITERAL_SUFFIX String {@code =>} suffix used to quote a literal (may be - * null) - *
    6. CREATE_PARAMS String {@code =>} parameters used in creating the type (may be - * null) - *
    7. NULLABLE short {@code =>} can you use NULL for this type. - *
        - *
      • typeNoNulls - does not allow NULL values - *
      • typeNullable - allows NULL values - *
      • typeNullableUnknown - nullability unknown - *
      - *
    8. CASE_SENSITIVE boolean{@code =>} is it case sensitive. - *
    9. SEARCHABLE short {@code =>} can you use "WHERE" based on this type: - *
        - *
      • typePredNone - No support - *
      • typePredChar - Only supported with WHERE .. LIKE - *
      • typePredBasic - Supported except for WHERE .. LIKE - *
      • typeSearchable - Supported for all WHERE .. - *
      - *
    10. UNSIGNED_ATTRIBUTE boolean {@code =>} is it unsigned. - *
    11. FIXED_PREC_SCALE boolean {@code =>} can it be a money value. - *
    12. AUTO_INCREMENT boolean {@code =>} can it be used for an auto-increment value. - *
    13. LOCAL_TYPE_NAME String {@code =>} localized version of type name (may be - * null) - *
    14. MINIMUM_SCALE short {@code =>} minimum scale supported - *
    15. MAXIMUM_SCALE short {@code =>} maximum scale supported - *
    16. SQL_DATA_TYPE int {@code =>} unused - *
    17. SQL_DATETIME_SUB int {@code =>} unused - *
    18. NUM_PREC_RADIX int {@code =>} usually 2 or 10
    + *
  9. TYPE_NAME String {@code =>} Type name + *
  10. DATA_TYPE int {@code =>} SQL data type from java.sql.Types + *
  11. PRECISION int {@code =>} maximum precision + *
  12. LITERAL_PREFIX String {@code =>} prefix used to quote a literal (may be null + * ) + *
  13. LITERAL_SUFFIX String {@code =>} suffix used to quote a literal (may be null + * ) + *
  14. CREATE_PARAMS String {@code =>} parameters used in creating the type (may be + * null) + *
  15. NULLABLE short {@code =>} can you use NULL for this type. + *
      + *
    • typeNoNulls - does not allow NULL values + *
    • typeNullable - allows NULL values + *
    • typeNullableUnknown - nullability unknown + *
    + *
  16. CASE_SENSITIVE boolean{@code =>} is it case sensitive. + *
  17. SEARCHABLE short {@code =>} can you use "WHERE" based on this type: + *
      + *
    • typePredNone - No support + *
    • typePredChar - Only supported with WHERE .. LIKE + *
    • typePredBasic - Supported except for WHERE .. LIKE + *
    • typeSearchable - Supported for all WHERE .. + *
    + *
  18. UNSIGNED_ATTRIBUTE boolean {@code =>} is it unsigned. + *
  19. FIXED_PREC_SCALE boolean {@code =>} can it be a money value. + *
  20. AUTO_INCREMENT boolean {@code =>} can it be used for an auto-increment value. + *
  21. LOCAL_TYPE_NAME String {@code =>} localized version of type name (may be + * null) + *
  22. MINIMUM_SCALE short {@code =>} minimum scale supported + *
  23. MAXIMUM_SCALE short {@code =>} maximum scale supported + *
  24. SQL_DATA_TYPE int {@code =>} unused + *
  25. SQL_DATETIME_SUB int {@code =>} unused + *
  26. NUM_PREC_RADIX int {@code =>} usually 2 or 10 + *
* *

The PRECISION column represents the maximum column size that the server supports for the - * given datatype. For numeric data, this is the maximum precision. For character data, this is + * given datatype. For numeric data, this is the maximum precision. For character data, this is * the length in characters. For datetime datatypes, this is the length in characters of the * String representation (assuming the maximum allowed precision of the fractional seconds * component). For binary data, this is the length in bytes. For the ROWID datatype, this is the - * length in bytes. Null is returned for data types where the column size is not applicable.

+ * length in bytes. Null is returned for data types where the column size is not applicable. * * @return a ResultSet object in which each row is an SQL type description */ public ResultSet getTypeInfo() { String[] columnNames = { - "TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", "LITERAL_SUFFIX", - "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", "UNSIGNED_ATTRIBUTE", - "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", "MAXIMUM_SCALE", - "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX" + "TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", "LITERAL_SUFFIX", + "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", "UNSIGNED_ATTRIBUTE", + "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", "MAXIMUM_SCALE", + "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX" }; ColumnType[] columnTypes = { - ColumnType.VARCHAR, ColumnType.INTEGER, ColumnType.INTEGER, ColumnType.VARCHAR, - ColumnType.VARCHAR, - ColumnType.VARCHAR, ColumnType.INTEGER, ColumnType.BIT, ColumnType.SMALLINT, ColumnType.BIT, - ColumnType.BIT, ColumnType.BIT, ColumnType.VARCHAR, ColumnType.SMALLINT, - ColumnType.SMALLINT, - ColumnType.INTEGER, ColumnType.INTEGER, ColumnType.INTEGER + ColumnType.VARCHAR, + ColumnType.INTEGER, + ColumnType.INTEGER, + ColumnType.VARCHAR, + ColumnType.VARCHAR, + ColumnType.VARCHAR, + ColumnType.INTEGER, + ColumnType.BIT, + ColumnType.SMALLINT, + ColumnType.BIT, + ColumnType.BIT, + ColumnType.BIT, + ColumnType.VARCHAR, + ColumnType.SMALLINT, + ColumnType.SMALLINT, + ColumnType.INTEGER, + ColumnType.INTEGER, + ColumnType.INTEGER }; String[][] data = { - {"BIT", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BIT", "0", "0", "0", "0", - "10"}, - {"BOOL", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BOOL", "0", "0", "0", "0", - "10"}, - {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "TINYINT", - "0", "0", "0", "0", "10"}, - {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", - "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "BIGINT", - "0", "0", "0", "0", "10"}, - {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", - "LONG VARBINARY", "0", - "0", "0", "0", "10"}, - {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", "MEDIUMBLOB", - "0", "0", - "0", "0", "10"}, - {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "1", "3", "0", "0", "0", "LONGBLOB", - "0", "0", "0", - "0", "10"}, - {"BLOB", "-4", "65535", "'", "'", "", "1", "1", "3", "0", "0", "0", "BLOB", "0", "0", "0", - "0", "10"}, - {"TINYBLOB", "-4", "255", "'", "'", "", "1", "1", "3", "0", "0", "0", "TINYBLOB", "0", "0", - "0", "0", - "10"}, - {"VARBINARY", "-3", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "VARBINARY", "0", - "0", "0", - "0", "10"}, - {"BINARY", "-2", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "BINARY", "0", "0", - "0", "0", - "10"}, - {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", - "LONG VARCHAR", "0", - "0", "0", "0", "10"}, - {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", "MEDIUMTEXT", - "0", "0", - "0", "0", "10"}, - {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "0", "3", "0", "0", "0", "LONGTEXT", - "0", "0", - "0", "0", "10"}, - {"TEXT", "-1", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "TEXT", "0", "0", "0", - "0", "10"}, - {"TINYTEXT", "-1", "255", "'", "'", "", "1", "0", "3", "0", "0", "0", "TINYTEXT", "0", "0", - "0", - "0", "10"}, - {"CHAR", "1", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "CHAR", "0", "0", "0", - "0", "10"}, - {"NUMERIC", "2", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "NUMERIC", - "-308", "308", "0", "0", "10"}, - {"DECIMAL", "3", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "DECIMAL", "-308", - "308", "0", "0", "10"}, - {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "INTEGER", - "0", "0", "0", "0", "10"}, - {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, - {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "INT", "0", - "0", "0", "0", "10"}, - {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "INT UNSIGNED", - "0", "0", "0", "0", "10"}, - {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "MEDIUMINT", "0", "0", "0", "0", "10"}, - {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "SMALLINT", - "0", "0", "0", "0", "10"}, - {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", - "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"FLOAT", "7", "10", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "FLOAT", - "-38", "38", - "0", "0", "10"}, - {"DOUBLE", "8", "17", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "DOUBLE", - "-308", - "308", "0", "0", "10"}, - {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, - {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "REAL", - "-308", - "308", "0", "0", "10"}, - {"VARCHAR", "12", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "VARCHAR", "0", "0", - "0", - "0", "10"}, - {"ENUM", "12", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "ENUM", "0", "0", "0", - "0", "10"}, - {"SET", "12", "64", "'", "'", "", "1", "0", "3", "0", "0", "0", "SET", "0", "0", "0", "0", - "10"}, - {"DATE", "91", "10", "'", "'", "", "1", "0", "3", "0", "0", "0", "DATE", "0", "0", "0", "0", - "10"}, - {"TIME", "92", "18", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIME", "0", "0", "0", - "0", "10"}, - {"DATETIME", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "DATETIME", "0", - "0", "0", - "0", "10"}, - {"TIMESTAMP", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIMESTAMP", "0", - "0", - "0", "0", "10"} + {"BIT", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BIT", "0", "0", "0", "0", "10"}, + { + "BOOL", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BOOL", "0", "0", "0", "0", + "10" + }, + { + "TINYINT", + "-6", + "3", + "", + "", + "[(M)] [UNSIGNED] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "TINYINT", + "0", + "0", + "0", + "0", + "10" + }, + { + "TINYINT UNSIGNED", + "-6", + "3", + "", + "", + "[(M)] [UNSIGNED] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "TINYINT UNSIGNED", + "0", + "0", + "0", + "0", + "10" + }, + { + "BIGINT", + "-5", + "19", + "", + "", + "[(M)] [UNSIGNED] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "BIGINT", + "0", + "0", + "0", + "0", + "10" + }, + { + "BIGINT UNSIGNED", + "-5", + "20", + "", + "", + "[(M)] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "BIGINT UNSIGNED", + "0", + "0", + "0", + "0", + "10" + }, + { + "LONG VARBINARY", + "-4", + "16777215", + "'", + "'", + "", + "1", + "1", + "3", + "0", + "0", + "0", + "LONG VARBINARY", + "0", + "0", + "0", + "0", + "10" + }, + { + "MEDIUMBLOB", + "-4", + "16777215", + "'", + "'", + "", + "1", + "1", + "3", + "0", + "0", + "0", + "MEDIUMBLOB", + "0", + "0", + "0", + "0", + "10" + }, + { + "LONGBLOB", + "-4", + "2147483647", + "'", + "'", + "", + "1", + "1", + "3", + "0", + "0", + "0", + "LONGBLOB", + "0", + "0", + "0", + "0", + "10" + }, + { + "BLOB", "-4", "65535", "'", "'", "", "1", "1", "3", "0", "0", "0", "BLOB", "0", "0", "0", + "0", "10" + }, + { + "TINYBLOB", + "-4", + "255", + "'", + "'", + "", + "1", + "1", + "3", + "0", + "0", + "0", + "TINYBLOB", + "0", + "0", + "0", + "0", + "10" + }, + { + "VARBINARY", + "-3", + "255", + "'", + "'", + "(M)", + "1", + "1", + "3", + "0", + "0", + "0", + "VARBINARY", + "0", + "0", + "0", + "0", + "10" + }, + { + "BINARY", "-2", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "BINARY", "0", "0", + "0", "0", "10" + }, + { + "LONG VARCHAR", + "-1", + "16777215", + "'", + "'", + "", + "1", + "0", + "3", + "0", + "0", + "0", + "LONG VARCHAR", + "0", + "0", + "0", + "0", + "10" + }, + { + "MEDIUMTEXT", + "-1", + "16777215", + "'", + "'", + "", + "1", + "0", + "3", + "0", + "0", + "0", + "MEDIUMTEXT", + "0", + "0", + "0", + "0", + "10" + }, + { + "LONGTEXT", + "-1", + "2147483647", + "'", + "'", + "", + "1", + "0", + "3", + "0", + "0", + "0", + "LONGTEXT", + "0", + "0", + "0", + "0", + "10" + }, + { + "TEXT", "-1", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "TEXT", "0", "0", "0", + "0", "10" + }, + { + "TINYTEXT", + "-1", + "255", + "'", + "'", + "", + "1", + "0", + "3", + "0", + "0", + "0", + "TINYTEXT", + "0", + "0", + "0", + "0", + "10" + }, + { + "CHAR", "1", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "CHAR", "0", "0", "0", + "0", "10" + }, + { + "NUMERIC", + "2", + "65", + "", + "", + "[(M,D])] [ZEROFILL]", + "1", + "0", + "3", + "0", + "0", + "1", + "NUMERIC", + "-308", + "308", + "0", + "0", + "10" + }, + { + "DECIMAL", + "3", + "65", + "", + "", + "[(M,D])] [ZEROFILL]", + "1", + "0", + "3", + "0", + "0", + "1", + "DECIMAL", + "-308", + "308", + "0", + "0", + "10" + }, + { + "INTEGER", + "4", + "10", + "", + "", + "[(M)] [UNSIGNED] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "INTEGER", + "0", + "0", + "0", + "0", + "10" + }, + { + "INTEGER UNSIGNED", + "4", + "10", + "", + "", + "[(M)] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "INTEGER UNSIGNED", + "0", + "0", + "0", + "0", + "10" + }, + { + "INT", + "4", + "10", + "", + "", + "[(M)] [UNSIGNED] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "INT", + "0", + "0", + "0", + "0", + "10" + }, + { + "INT UNSIGNED", + "4", + "10", + "", + "", + "[(M)] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "INT UNSIGNED", + "0", + "0", + "0", + "0", + "10" + }, + { + "MEDIUMINT", + "4", + "7", + "", + "", + "[(M)] [UNSIGNED] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "MEDIUMINT", + "0", + "0", + "0", + "0", + "10" + }, + { + "MEDIUMINT UNSIGNED", + "4", + "8", + "", + "", + "[(M)] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "MEDIUMINT UNSIGNED", + "0", + "0", + "0", + "0", + "10" + }, + { + "SMALLINT", + "5", + "5", + "", + "", + "[(M)] [UNSIGNED] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "SMALLINT", + "0", + "0", + "0", + "0", + "10" + }, + { + "SMALLINT UNSIGNED", + "5", + "5", + "", + "", + "[(M)] [ZEROFILL]", + "1", + "0", + "3", + "1", + "0", + "1", + "SMALLINT UNSIGNED", + "0", + "0", + "0", + "0", + "10" + }, + { + "FLOAT", + "7", + "10", + "", + "", + "[(M|D)] [ZEROFILL]", + "1", + "0", + "3", + "0", + "0", + "1", + "FLOAT", + "-38", + "38", + "0", + "0", + "10" + }, + { + "DOUBLE", + "8", + "17", + "", + "", + "[(M|D)] [ZEROFILL]", + "1", + "0", + "3", + "0", + "0", + "1", + "DOUBLE", + "-308", + "308", + "0", + "0", + "10" + }, + { + "DOUBLE PRECISION", + "8", + "17", + "", + "", + "[(M,D)] [ZEROFILL]", + "1", + "0", + "3", + "0", + "0", + "1", + "DOUBLE PRECISION", + "-308", + "308", + "0", + "0", + "10" + }, + { + "REAL", + "8", + "17", + "", + "", + "[(M,D)] [ZEROFILL]", + "1", + "0", + "3", + "0", + "0", + "1", + "REAL", + "-308", + "308", + "0", + "0", + "10" + }, + { + "VARCHAR", "12", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "VARCHAR", "0", "0", + "0", "0", "10" + }, + { + "ENUM", "12", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "ENUM", "0", "0", "0", + "0", "10" + }, + { + "SET", "12", "64", "'", "'", "", "1", "0", "3", "0", "0", "0", "SET", "0", "0", "0", "0", + "10" + }, + { + "DATE", "91", "10", "'", "'", "", "1", "0", "3", "0", "0", "0", "DATE", "0", "0", "0", "0", + "10" + }, + { + "TIME", "92", "18", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIME", "0", "0", "0", + "0", "10" + }, + { + "DATETIME", + "93", + "27", + "'", + "'", + "[(M)]", + "1", + "0", + "3", + "0", + "0", + "0", + "DATETIME", + "0", + "0", + "0", + "0", + "10" + }, + { + "TIMESTAMP", + "93", + "27", + "'", + "'", + "[(M)]", + "1", + "0", + "3", + "0", + "0", + "0", + "TIMESTAMP", + "0", + "0", + "0", + "0", + "10" + } }; - return SelectResultSet - .createResultSet(columnNames, columnTypes, data, connection.getProtocol()); + return SelectResultSet.createResultSet( + columnNames, columnTypes, data, connection.getProtocol()); } /** * Retrieves a description of the given table's indices and statistics. They are ordered by * NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION. * - *

Each index column description has the following columns:

+ *

Each index column description has the following columns: * *

    - *
  1. TABLE_CAT String {@code =>} table catalog (may be null)
  2. - *
  3. TABLE_SCHEM String {@code =>} table schema (may be null)
  4. - *
  5. TABLE_NAME String {@code =>} table name
  6. - *
  7. NON_UNIQUE boolean {@code =>} Can index values be non-unique. false when TYPE is - * tableIndexStatistic
  8. - *
  9. INDEX_QUALIFIER String {@code =>} index catalog (may be null); - * null - * when TYPE is tableIndexStatistic
  10. - *
  11. INDEX_NAME String {@code =>} index name; null when TYPE is - * tableIndexStatistic
  12. - *
  13. TYPE short {@code =>} index type: - *
      - *
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction - * with a table's index descriptions - *
    • tableIndexClustered - this is a clustered index - *
    • tableIndexHashed - this is a hashed index - *
    • tableIndexOther - this is some other style of index - *
    - *
  14. - *
  15. ORDINAL_POSITION short {@code =>} column sequence number within index; zero when - * TYPE is tableIndexStatistic
  16. COLUMN_NAME String {@code =>} column name; - * null when TYPE is tableIndexStatistic
  17. - *
  18. ASC_OR_DESC String {@code =>} column sort sequence, "A" {@code =>} ascending, "D" - * {@code =>} descending, may be null if sort sequence is not supported; - * null when TYPE is tableIndexStatistic
  19. CARDINALITY long {@code =>} - * When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it - * is the number of unique values in the index.
  20. - *
  21. PAGES long {@code =>} When TYPE is tableIndexStatisic then this is the number of - * pages used for the table, otherwise it is the number of pages used for the current index.
  22. - *
  23. FILTER_CONDITION String {@code =>} Filter condition, if any. (may be - * null)
  24. + *
  25. TABLE_CAT String {@code =>} table catalog (may be null) + *
  26. TABLE_SCHEM String {@code =>} table schema (may be null) + *
  27. TABLE_NAME String {@code =>} table name + *
  28. NON_UNIQUE boolean {@code =>} Can index values be non-unique. false when TYPE is + * tableIndexStatistic + *
  29. INDEX_QUALIFIER String {@code =>} index catalog (may be null); + * null when TYPE is tableIndexStatistic + *
  30. INDEX_NAME String {@code =>} index name; null when TYPE is + * tableIndexStatistic + *
  31. TYPE short {@code =>} index type: + *
      + *
    • tableIndexStatistic - this identifies table statistics that are returned in + * conjuction with a table's index descriptions + *
    • tableIndexClustered - this is a clustered index + *
    • tableIndexHashed - this is a hashed index + *
    • tableIndexOther - this is some other style of index + *
    + *
  32. ORDINAL_POSITION short {@code =>} column sequence number within index; zero when + * TYPE is tableIndexStatistic + *
  33. COLUMN_NAME String {@code =>} column name; null when TYPE is + * tableIndexStatistic + *
  34. ASC_OR_DESC String {@code =>} column sort sequence, "A" {@code =>} ascending, "D" + * {@code =>} descending, may be null if sort sequence is not supported; + * null when TYPE is tableIndexStatistic + *
  35. CARDINALITY long {@code =>} When TYPE is tableIndexStatistic, then this is the + * number of rows in the table; otherwise, it is the number of unique values in the index. + *
  36. PAGES long {@code =>} When TYPE is tableIndexStatisic then this is the number of + * pages used for the table, otherwise it is the number of pages used for the current index. + *
  37. FILTER_CONDITION String {@code =>} Filter condition, if any. (may be null + * ) *
* - * @param catalog a catalog name; must match the catalog name as it is stored in this - * database; "" retrieves those without a catalog; null means that - * the catalog name should not be used to narrow the search - * @param schema a schema name; must match the schema name as it is stored in this database; - * "" retrieves those without a schema; null means that the schema - * name should not be used to narrow the search - * @param table a table name; must match the table name as it is stored in this database - * @param unique when true, return only indices for unique values; when false, return indices - * regardless of whether unique or not + * @param catalog a catalog name; must match the catalog name as it is stored in this database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schema a schema name; must match the schema name as it is stored in this database; "" + * retrieves those without a schema; null means that the schema name should not + * be used to narrow the search + * @param table a table name; must match the table name as it is stored in this database + * @param unique when true, return only indices for unique values; when false, return indices + * regardless of whether unique or not * @param approximate when true, result is allowed to reflect approximate or out of data values; - * when false, results are requested to be accurate + * when false, results are requested to be accurate * @return ResultSet - each row is an index column description * @throws SQLException if a database access error occurs */ - public ResultSet getIndexInfo(String catalog, String schema, String table, - boolean unique, boolean approximate) throws SQLException { + public ResultSet getIndexInfo( + String catalog, String schema, String table, boolean unique, boolean approximate) + throws SQLException { String sql = "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, NON_UNIQUE, " @@ -2694,7 +3410,8 @@ public ResultSet getIndexInfo(String catalog, String schema, String table, + " SEQ_IN_INDEX ORDINAL_POSITION, COLUMN_NAME, COLLATION ASC_OR_DESC," + " CARDINALITY, NULL PAGES, NULL FILTER_CONDITION" + " FROM INFORMATION_SCHEMA.STATISTICS" - + " WHERE TABLE_NAME = " + escapeQuote(table) + + " WHERE TABLE_NAME = " + + escapeQuote(table) + " AND " + catalogCond("TABLE_SCHEMA", catalog) + ((unique) ? " AND NON_UNIQUE = 0" : "") @@ -2708,11 +3425,12 @@ public ResultSet getIndexInfo(String catalog, String schema, String table, * and ResultSet.TYPE_SCROLL_INSENSITIVE are supported. * * @param type one of the following ResultSet constants: - *
    - *
  • ResultSet.TYPE_FORWARD_ONLY
  • - *
  • ResultSet.TYPE_SCROLL_INSENSITIVE
  • - *
  • ResultSet.TYPE_SCROLL_SENSITIVE
  • - *
+ *
    + *
  • ResultSet.TYPE_FORWARD_ONLY + *
  • ResultSet.TYPE_SCROLL_INSENSITIVE + *
  • ResultSet.TYPE_SCROLL_SENSITIVE + *
+ * * @return true if supported */ public boolean supportsResultSetType(int type) { @@ -2724,22 +3442,24 @@ public boolean supportsResultSetType(int type) { * given result set type. All are supported, but combination that use * ResultSet.TYPE_SCROLL_INSENSITIVE. * - * @param type one of the following ResultSet constants: - *
    - *
  • ResultSet.TYPE_FORWARD_ONLY
  • - *
  • ResultSet.TYPE_SCROLL_INSENSITIVE
  • - *
  • ResultSet.TYPE_SCROLL_SENSITIVE
  • - *
+ * @param type one of the following ResultSet constants: + *
    + *
  • ResultSet.TYPE_FORWARD_ONLY + *
  • ResultSet.TYPE_SCROLL_INSENSITIVE + *
  • ResultSet.TYPE_SCROLL_SENSITIVE + *
+ * * @param concurrency one of the following ResultSet constants: - *
    - *
  • ResultSet.CONCUR_READ_ONLY
  • - *
  • ResultSet.CONCUR_UPDATABLE
  • - *
+ *
    + *
  • ResultSet.CONCUR_READ_ONLY + *
  • ResultSet.CONCUR_UPDATABLE + *
+ * * @return true if supported */ public boolean supportsResultSetConcurrency(int type, int concurrency) { - //Support all concurrency (ResultSet.CONCUR_READ_ONLY and ResultSet.CONCUR_UPDATABLE) - //so just return scroll type + // Support all concurrency (ResultSet.CONCUR_READ_ONLY and ResultSet.CONCUR_UPDATABLE) + // so just return scroll type return type == ResultSet.TYPE_SCROLL_INSENSITIVE || type == ResultSet.TYPE_FORWARD_ONLY; } @@ -2785,54 +3505,50 @@ public boolean supportsBatchUpdates() { /** * Retrieves a description of the user-defined types (UDTs) defined in a particular schema. - * Schema-specific UDTs may have type JAVA_OBJECT, STRUCT, or - * DISTINCT. + * Schema-specific UDTs may have type JAVA_OBJECT, STRUCT, or + * DISTINCT. * - *

Only types matching the catalog, schema, type name and type criteria - * are returned. They are ordered by DATA_TYPE, TYPE_CAT, - * TYPE_SCHEM and - * TYPE_NAME. The type name parameter may be a fully-qualified name. - * In this case, the catalog and schemaPattern parameters are ignored.

+ *

Only types matching the catalog, schema, type name and type criteria are returned. They are + * ordered by DATA_TYPE, TYPE_CAT, TYPE_SCHEM and + * TYPE_NAME. The type name parameter may be a fully-qualified name. In this case, the + * catalog and schemaPattern parameters are ignored. * - *

Each type description has the following columns:

+ *

Each type description has the following columns: * *

    - *
  1. TYPE_CAT String {@code =>} the type's catalog (may be null)
  2. - *
  3. TYPE_SCHEM String {@code =>} type's schema (may be null)
  4. - *
  5. TYPE_NAME String {@code =>} type name
  6. - *
  7. CLASS_NAME String {@code =>} Java class name
  8. - *
  9. DATA_TYPE int {@code =>} type value defined in java.sql.Types. One of JAVA_OBJECT, - * STRUCT, or DISTINCT
  10. - *
  11. REMARKS String {@code =>} explanatory comment on the type
  12. - *
  13. BASE_TYPE short {@code =>} type code of the source type of a DISTINCT type or the - * type that implements the user-generated reference type of the SELF_REFERENCING_COLUMN of a - * structured type as defined in java.sql.Types (null if DATA_TYPE is not DISTINCT or - * not STRUCT with REFERENCE_GENERATION = USER_DEFINED)
  14. + *
  15. TYPE_CAT String {@code =>} the type's catalog (may be null) + *
  16. TYPE_SCHEM String {@code =>} type's schema (may be null) + *
  17. TYPE_NAME String {@code =>} type name + *
  18. CLASS_NAME String {@code =>} Java class name + *
  19. DATA_TYPE int {@code =>} type value defined in java.sql.Types. One of JAVA_OBJECT, + * STRUCT, or DISTINCT + *
  20. REMARKS String {@code =>} explanatory comment on the type + *
  21. BASE_TYPE short {@code =>} type code of the source type of a DISTINCT type or the + * type that implements the user-generated reference type of the SELF_REFERENCING_COLUMN of + * a structured type as defined in java.sql.Types (null if DATA_TYPE is not + * DISTINCT or not STRUCT with REFERENCE_GENERATION = USER_DEFINED) *
* - *

Note: If the driver does not support UDTs, an empty result set is returned.

+ *

Note: If the driver does not support UDTs, an empty result set is returned. * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; - * null means that the catalog name should not be used to - * narrow the search - * @param schemaPattern a schema pattern name; must match the schema name as it is stored in the - * database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema pattern name; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search * @param typeNamePattern a type name pattern; must match the type name as it is stored in the - * database; may be a fully qualified name - * @param types a list of user-defined types (JAVA_OBJECT, STRUCT, or DISTINCT) to - * include; - * null returns all types + * database; may be a fully qualified name + * @param types a list of user-defined types (JAVA_OBJECT, STRUCT, or DISTINCT) to include; + * null returns all types * @return ResultSet object in which each row describes a UDT * @throws SQLException if a database access error occurs * @see #getSearchStringEscape * @since 1.2 */ @Override - public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, - int[] types) + public ResultSet getUDTs( + String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { String sql = "SELECT ' ' TYPE_CAT, NULL TYPE_SCHEM, ' ' TYPE_NAME, ' ' CLASS_NAME, 0 DATA_TYPE, ' ' REMARKS, 0 BASE_TYPE" @@ -2870,26 +3586,27 @@ public boolean supportsGetGeneratedKeys() { * have a direct super type, it is not listed here. A row of the ResultSet object * returned by this method describes the designated UDT and a direct supertype. A row has the * following columns: + * *

    - *
  1. TYPE_CAT String {@code =>} the UDT's catalog (may - * be null)
  2. TYPE_SCHEM String {@code =>} UDT's schema (may be - * null) - *
  3. TYPE_NAME String {@code =>} type name of the UDT
  4. SUPERTYPE_CAT - * String {@code =>} the direct super type's catalog (may be null) - *
  5. SUPERTYPE_SCHEM String {@code =>} the direct super type's schema (may be - * null) - *
  6. SUPERTYPE_NAME String {@code - * =>} the direct super type's name
- * - *

Note: If the driver does not support type hierarchies, an empty result set is - * returned.

- * - * @param catalog a catalog name; "" retrieves those without a catalog; null - * means drop catalog name from the selection criteria - * @param schemaPattern a schema name pattern; "" retrieves those without a schema + *
  • TYPE_CAT String {@code =>} the UDT's catalog (may be null) + *
  • TYPE_SCHEM String {@code =>} UDT's schema (may be null) + *
  • TYPE_NAME String {@code =>} type name of the UDT + *
  • SUPERTYPE_CAT String {@code =>} the direct super type's catalog (may be null + * ) + *
  • SUPERTYPE_SCHEM String {@code =>} the direct super type's schema (may be + * null) + *
  • SUPERTYPE_NAME String {@code =>} the direct super type's name + * + * + *

    Note: If the driver does not support type hierarchies, an empty result set is + * returned. + * + * @param catalog a catalog name; "" retrieves those without a catalog; null means + * drop catalog name from the selection criteria + * @param schemaPattern a schema name pattern; "" retrieves those without a schema * @param typeNamePattern a UDT name pattern; may be a fully-qualified name * @return a ResultSet object in which a row gives information about the designated - * UDT + * UDT * @throws SQLException if a database access error occurs * @see #getSearchStringEscape * @since 1.4 @@ -2907,27 +3624,27 @@ public ResultSet getSuperTypes(String catalog, String schemaPattern, String type * Retrieves a description of the table hierarchies defined in a particular schema in this * database. * - *

    Only supertable information for tables matching the catalog, schema and table name are + *

    Only supertable information for tables matching the catalog, schema and table name are * returned. The table name parameter may be a fully-qualified name, in which case, the catalog * and schemaPattern parameters are ignored. If a table does not have a super table, it is not * listed here. Supertables have to be defined in the same catalog and schema as the sub tables. - * Therefore, the type description does not need to include this information for the - * supertable.

    - * - *

    Each type description has the following columns:

    - *
    1. TABLE_CAT String {@code - * =>} the type's catalog (may be null) - *
    2. TABLE_SCHEM String {@code =>} type's schema (may be null) - *
    3. TABLE_NAME String - * {@code =>} type name - *
    4. SUPERTABLE_NAME String {@code =>} the direct super type's name
    - * - *

    Note: If the driver does not support type hierarchies, an empty result set is - * returned.

    - * - * @param catalog a catalog name; "" retrieves those without a catalog; null - * means drop catalog name from the selection criteria - * @param schemaPattern a schema name pattern; "" retrieves those without a schema + * Therefore, the type description does not need to include this information for the supertable. + * + *

    Each type description has the following columns: + * + *

      + *
    1. TABLE_CAT String {@code =>} the type's catalog (may be null) + *
    2. TABLE_SCHEM String {@code =>} type's schema (may be null) + *
    3. TABLE_NAME String {@code =>} type name + *
    4. SUPERTABLE_NAME String {@code =>} the direct super type's name + *
    + * + *

    Note: If the driver does not support type hierarchies, an empty result set is + * returned. + * + * @param catalog a catalog name; "" retrieves those without a catalog; null means + * drop catalog name from the selection criteria + * @param schemaPattern a schema name pattern; "" retrieves those without a schema * @param tableNamePattern a table name pattern; may be a fully-qualified name * @return a ResultSet object in which each row is a type description * @throws SQLException if a database access error occurs @@ -2945,70 +3662,73 @@ public ResultSet getSuperTables(String catalog, String schemaPattern, String tab * Retrieves a description of the given attribute of the given type for a user-defined type (UDT) * that is available in the given schema and catalog. Descriptions are returned only for * attributes of UDTs matching the catalog, schema, type, and attribute name criteria. They are - * ordered by TYPE_CAT, TYPE_SCHEM, TYPE_NAME and - * ORDINAL_POSITION. This description does not contain inherited attributes. - * The ResultSet object that is returned has the following columns:

      - *
    1. TYPE_CAT String {@code =>} type catalog (may be null) - *
    2. TYPE_SCHEM String {@code =>} type schema (may be null) - *
    3. TYPE_NAME String {@code =>} type name
    4. ATTR_NAME String {@code =>} - * attribute name
    5. DATA_TYPE int {@code =>} attribute type SQL type from java.sql.Types - *
    6. ATTR_TYPE_NAME String {@code =>} Data source dependent type name. For a UDT, the - * type name is fully qualified. For a REF, the type name is fully qualified and represents the - * target type of the reference type. - *
    7. ATTR_SIZE int {@code =>} column size. For char or date types this is the maximum - * number of characters; for numeric or decimal types this is precision.
    8. DECIMAL_DIGITS - * int {@code =>} the number of fractional digits. Null is returned for data types where - * DECIMAL_DIGITS is not applicable. - *
    9. NUM_PREC_RADIX int {@code =>} Radix (typically either 10 or 2)
    10. NULLABLE - * int {@code =>} whether NULL is allowed
      • attributeNoNulls - might not allow NULL - * values - *
      • attributeNullable - definitely allows NULL values - *
      • attributeNullableUnknown - nullability unknown - *
      - *
    11. REMARKS String {@code =>} comment describing column (may be null) - *
    12. ATTR_DEF String {@code =>} default value (may benull) - *
    13. SQL_DATA_TYPE int {@code =>} unused
    14. SQL_DATETIME_SUB int {@code =>} - * unused - *
    15. CHAR_OCTET_LENGTH int {@code =>} for char types the maximum number of bytes in the - * column - *
    16. ORDINAL_POSITION int {@code =>} index of the attribute in the UDT (starting at 1) - *
    17. IS_NULLABLE String {@code =>} ISO rules are used to determine the nullability for - * a attribute. - *
        - *
      • YES --- if the attribute can include NULLs - *
      • NO --- if the attribute cannot include NULLs - *
      • empty string --- if the nullability for the attribute is unknown - *
      - *
    18. SCOPE_CATALOG String {@code =>} catalog of table that is the scope of a reference - * attribute (null if DATA_TYPE isn't REF) - *
    19. SCOPE_SCHEMA String {@code =>} schema of table that is the scope of a reference - * attribute (null if DATA_TYPE isn't REF) - *
    20. SCOPE_TABLE String {@code =>} table name that is the scope of a reference attribute - * (null if the DATA_TYPE isn't REF) - *
    21. SOURCE_DATA_TYPE short {@code =>} source type of a distinct type or user-generated - * Ref type,SQL type from java.sql.Types (null if DATA_TYPE isn't DISTINCT or - * user-generated REF) + * ordered by TYPE_CAT, TYPE_SCHEM, TYPE_NAME and + * ORDINAL_POSITION. This description does not contain inherited attributes. The + * ResultSet object that is returned has the following columns: + * + *
        + *
      1. TYPE_CAT String {@code =>} type catalog (may be null) + *
      2. TYPE_SCHEM String {@code =>} type schema (may be null) + *
      3. TYPE_NAME String {@code =>} type name + *
      4. ATTR_NAME String {@code =>} attribute name + *
      5. DATA_TYPE int {@code =>} attribute type SQL type from java.sql.Types + *
      6. ATTR_TYPE_NAME String {@code =>} Data source dependent type name. For a UDT, the + * type name is fully qualified. For a REF, the type name is fully qualified and represents + * the target type of the reference type. + *
      7. ATTR_SIZE int {@code =>} column size. For char or date types this is the maximum + * number of characters; for numeric or decimal types this is precision. + *
      8. DECIMAL_DIGITS int {@code =>} the number of fractional digits. Null is returned + * for data types where DECIMAL_DIGITS is not applicable. + *
      9. NUM_PREC_RADIX int {@code =>} Radix (typically either 10 or 2) + *
      10. NULLABLE int {@code =>} whether NULL is allowed + *
          + *
        • attributeNoNulls - might not allow NULL values + *
        • attributeNullable - definitely allows NULL values + *
        • attributeNullableUnknown - nullability unknown + *
        + *
      11. REMARKS String {@code =>} comment describing column (may be null) + *
      12. ATTR_DEF String {@code =>} default value (may benull) + *
      13. SQL_DATA_TYPE int {@code =>} unused + *
      14. SQL_DATETIME_SUB int {@code =>} unused + *
      15. CHAR_OCTET_LENGTH int {@code =>} for char types the maximum number of bytes in the + * column + *
      16. ORDINAL_POSITION int {@code =>} index of the attribute in the UDT (starting at 1) + *
      17. IS_NULLABLE String {@code =>} ISO rules are used to determine the nullability for + * a attribute. + *
          + *
        • YES --- if the attribute can include NULLs + *
        • NO --- if the attribute cannot include NULLs + *
        • empty string --- if the nullability for the attribute is unknown + *
        + *
      18. SCOPE_CATALOG String {@code =>} catalog of table that is the scope of a reference + * attribute (null if DATA_TYPE isn't REF) + *
      19. SCOPE_SCHEMA String {@code =>} schema of table that is the scope of a reference + * attribute (null if DATA_TYPE isn't REF) + *
      20. SCOPE_TABLE String {@code =>} table name that is the scope of a reference + * attribute (null if the DATA_TYPE isn't REF) + *
      21. SOURCE_DATA_TYPE short {@code =>} source type of a distinct type or user-generated + * Ref type,SQL type from java.sql.Types (null if DATA_TYPE isn't DISTINCT or + * user-generated REF) *
      * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; null - * means that the catalog name should not be used to narrow the - * search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored - * in the database; "" retrieves those without a schema; - * null means that the schema name should not be used to - * narrow the search - * @param typeNamePattern a type name pattern; must match the type name as it is stored in - * the database + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search + * @param typeNamePattern a type name pattern; must match the type name as it is stored in the + * database * @param attributeNamePattern an attribute name pattern; must match the attribute name as it is - * declared in the database + * declared in the database * @return a ResultSet object in which each row is an attribute description * @throws SQLException if a database access error occurs * @see #getSearchStringEscape * @since 1.4 */ - public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, - String attributeNamePattern) throws SQLException { + public ResultSet getAttributes( + String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) + throws SQLException { String sql = "SELECT ' ' TYPE_CAT, ' ' TYPE_SCHEM, ' ' TYPE_NAME, ' ' ATTR_NAME, 0 DATA_TYPE," @@ -3076,15 +3796,15 @@ public boolean autoCommitFailureClosesAllResultSets() { /** * Retrieves a list of the client info properties that the driver supports. The result set * contains the following columns + * *
        - *
      1. NAME String : The name of the client info property
      2. - *
      3. MAX_LEN int : The maximum length of the value for the property
      4. - *
      5. DEFAULT_VALUE String : The default value of the property
      6. - *
      7. DESCRIPTION String : A description of the property. - * This will typically contain information as to where this property is stored in the - * database.
      8. + *
      9. NAME String : The name of the client info property + *
      10. MAX_LEN int : The maximum length of the value for the property + *
      11. DEFAULT_VALUE String : The default value of the property + *
      12. DESCRIPTION String : A description of the property. This will typically contain + * information as to where this property is stored in the database. *
      - * The ResultSet is sorted by the NAME column + *

      The ResultSet is sorted by the NAME column

      * * @return A ResultSet object; each row is a supported client info property */ @@ -3095,72 +3815,92 @@ public ResultSet getClientInfoProperties() { columns[2] = ColumnInformation.create("DEFAULT_VALUE", ColumnType.STRING); columns[3] = ColumnInformation.create("DESCRIPTION", ColumnType.STRING); - byte[] sixteenMb = new byte[]{(byte) 49, (byte) 54, (byte) 55, (byte) 55, (byte) 55, (byte) 50, - (byte) 49, (byte) 53}; + byte[] sixteenMb = + new byte[] { + (byte) 49, (byte) 54, (byte) 55, (byte) 55, (byte) 55, (byte) 50, (byte) 49, (byte) 53 + }; byte[] empty = new byte[0]; - ColumnType[] types = new ColumnType[]{ColumnType.STRING, ColumnType.INTEGER, ColumnType.STRING, - ColumnType.STRING}; + ColumnType[] types = + new ColumnType[] { + ColumnType.STRING, ColumnType.INTEGER, ColumnType.STRING, ColumnType.STRING + }; List rows = new ArrayList<>(3); - rows.add(StandardPacketInputStream.create(new byte[][]{ - "ApplicationName".getBytes(), sixteenMb, empty, - "The name of the application currently utilizing the connection".getBytes()}, types)); - - rows.add(StandardPacketInputStream.create(new byte[][]{ - "ClientUser".getBytes(), sixteenMb, empty, - ("The name of the user that the application using the connection is performing work for. " - + "This may not be the same as the user name that was used in establishing the connection.").getBytes()}, - types)); - - rows.add(StandardPacketInputStream.create(new byte[][]{ - "ClientHostname".getBytes(), sixteenMb, empty, - "The hostname of the computer the application using the connection is running on".getBytes()}, - types)); - - return new SelectResultSet(columns, rows, connection.getProtocol(), - ResultSet.TYPE_SCROLL_INSENSITIVE); + rows.add( + StandardPacketInputStream.create( + new byte[][] { + "ApplicationName".getBytes(), + sixteenMb, + empty, + "The name of the application currently utilizing the connection".getBytes() + }, + types)); + + rows.add( + StandardPacketInputStream.create( + new byte[][] { + "ClientUser".getBytes(), + sixteenMb, + empty, + ("The name of the user that the application using the connection is performing work for. " + + "This may not be the same as the user name that was used in establishing the connection.") + .getBytes() + }, + types)); + + rows.add( + StandardPacketInputStream.create( + new byte[][] { + "ClientHostname".getBytes(), + sixteenMb, + empty, + "The hostname of the computer the application using the connection is running on" + .getBytes() + }, + types)); + + return new SelectResultSet( + columns, rows, connection.getProtocol(), ResultSet.TYPE_SCROLL_INSENSITIVE); } /** - * Retrieves a description of the system and user functions available in the given catalog. Only + * Retrieves a description of the system and user functions available in the given catalog. Only * system and user function descriptions matching the schema and function name criteria are - * returned. They are ordered by FUNCTION_CAT, FUNCTION_SCHEM, - * FUNCTION_NAME and - * SPECIFIC_ NAME. + * returned. They are ordered by FUNCTION_CAT, FUNCTION_SCHEM, + * FUNCTION_NAME and SPECIFIC_ NAME. * - *

      Each function description has the the following columns:

      + *

      Each function description has the the following columns: * *

        - *
      1. FUNCTION_CAT String {@code =>} function catalog (may be null)
      2. - *
      3. FUNCTION_SCHEM String {@code =>} function schema (may be null)
      4. - *
      5. FUNCTION_NAME String {@code =>} function name. This is the name used to invoke - * the function
      6. - *
      7. REMARKS String {@code =>} explanatory comment on the function
      8. - *
      9. FUNCTION_TYPE short {@code =>} kind of function: - *
          - *
        • functionResultUnknown - Cannot determine if a return value or table will be - * returned
        • - *
        • functionNoTable- Does not return a table
        • - *
        • functionReturnsTable - Returns a table
        • - *
        - *
      10. - *
      11. SPECIFIC_NAME String {@code =>} the name which uniquely identifies this function - * within its schema. This is a user specified, or DBMS generated, name that may be different - * then the FUNCTION_NAME for example with overload functions
      12. + *
      13. FUNCTION_CAT String {@code =>} function catalog (may be null) + *
      14. FUNCTION_SCHEM String {@code =>} function schema (may be null) + *
      15. FUNCTION_NAME String {@code =>} function name. This is the name used to invoke the + * function + *
      16. REMARKS String {@code =>} explanatory comment on the function + *
      17. FUNCTION_TYPE short {@code =>} kind of function: + *
          + *
        • functionResultUnknown - Cannot determine if a return value or table will be + * returned + *
        • functionNoTable- Does not return a table + *
        • functionReturnsTable - Returns a table + *
        + *
      18. SPECIFIC_NAME String {@code =>} the name which uniquely identifies this function + * within its schema. This is a user specified, or DBMS generated, name that may be + * different then the FUNCTION_NAME for example with overload functions *
      * - *

      A user may not have - * permission to execute any of the functions that are returned by getFunctions

      + *

      A user may not have permission to execute any of the functions that are returned by + * getFunctions * - * @param catalog a catalog name; must match the catalog name as it is stored in the - * database; "" retrieves those without a catalog; null - * means that the catalog name should not be used to narrow the search - * @param schemaPattern a schema name pattern; must match the schema name as it is stored in - * the database; "" retrieves those without a schema; null - * means that the schema name should not be used to narrow the search + * @param catalog a catalog name; must match the catalog name as it is stored in the database; "" + * retrieves those without a catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern a schema name pattern; must match the schema name as it is stored in the + * database; "" retrieves those without a schema; null means that the schema name + * should not be used to narrow the search * @param functionNamePattern a function name pattern; must match the function name as it is - * stored in the database + * stored in the database * @return ResultSet - each row is a function description * @throws SQLException if a database access error occurs * @see #getSearchStringEscape @@ -3170,7 +3910,9 @@ public ResultSet getFunctions(String catalog, String schemaPattern, String funct throws SQLException { String sql = "SELECT ROUTINE_SCHEMA FUNCTION_CAT,NULL FUNCTION_SCHEM, ROUTINE_NAME FUNCTION_NAME," - + " ROUTINE_COMMENT REMARKS," + functionNoTable + " FUNCTION_TYPE, SPECIFIC_NAME " + + " ROUTINE_COMMENT REMARKS," + + functionNoTable + + " FUNCTION_TYPE, SPECIFIC_NAME " + " FROM INFORMATION_SCHEMA.ROUTINES " + " WHERE " + catalogCond("ROUTINE_SCHEMA", catalog) @@ -3198,5 +3940,4 @@ public long getMaxLogicalLobSize() { public boolean supportsRefCursors() { return false; } - } diff --git a/src/main/java/org/mariadb/jdbc/ServerSidePreparedStatement.java b/src/main/java/org/mariadb/jdbc/ServerSidePreparedStatement.java index 2e379ff31..0173675cb 100644 --- a/src/main/java/org/mariadb/jdbc/ServerSidePreparedStatement.java +++ b/src/main/java/org/mariadb/jdbc/ServerSidePreparedStatement.java @@ -3,7 +3,7 @@ * MariaDB Client for Java * * Copyright (c) 2012-2014 Monty Program Ab. - * Copyright (c) 2015-2017 MariaDB Ab. + * Copyright (c) 2015-2019 MariaDB Ab. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/BooleanParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/BooleanParameter.java index 8aac9f390..65c9dad4c 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/BooleanParameter.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/BooleanParameter.java @@ -22,10 +22,10 @@ package org.mariadb.jdbc.internal.com.send.parameters; +import java.io.IOException; import org.mariadb.jdbc.internal.ColumnType; import org.mariadb.jdbc.internal.io.output.PacketOutputStream; -import java.io.IOException; public class BooleanParameter implements Cloneable, ParameterHolder { @@ -69,5 +69,4 @@ public boolean isNullData() { public boolean isLongData() { return false; } - } diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ByteParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ByteParameter.java index 0a8e0252f..80285ae2e 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ByteParameter.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/ByteParameter.java @@ -65,6 +65,12 @@ public ByteParameter(byte value) { this.value = value & 0xFF; } + /** + * Write Byte value to stream using TEXT protocol. + * + * @param os the stream to write to + * @throws IOException if any socket error occur + */ public void writeTo(final PacketOutputStream os) throws IOException { os.write("0x"); os.write(hexArray[value >>> 4]); diff --git a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/LocalTimeParameter.java b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/LocalTimeParameter.java index 9f901aa99..3697e266c 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/LocalTimeParameter.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/send/parameters/LocalTimeParameter.java @@ -21,14 +21,12 @@ * */ - package org.mariadb.jdbc.internal.com.send.parameters; -import org.mariadb.jdbc.internal.ColumnType; -import org.mariadb.jdbc.internal.io.output.PacketOutputStream; - import java.io.IOException; import java.time.LocalTime; +import org.mariadb.jdbc.internal.ColumnType; +import org.mariadb.jdbc.internal.io.output.PacketOutputStream; public class LocalTimeParameter implements Cloneable, ParameterHolder { @@ -38,7 +36,7 @@ public class LocalTimeParameter implements Cloneable, ParameterHolder { /** * Constructor. * - * @param time time to write + * @param time time to write * @param fractionalSeconds must fractional seconds be send. */ public LocalTimeParameter(LocalTime time, boolean fractionalSeconds) { @@ -54,12 +52,12 @@ public LocalTimeParameter(LocalTime time, boolean fractionalSeconds) { public void writeTo(final PacketOutputStream pos) throws IOException { StringBuilder dateString = new StringBuilder(15); dateString - .append(time.getHour() < 10 ? "0" : "") - .append(time.getHour()) - .append(time.getMinute() < 10 ? ":0" : ":") - .append(time.getMinute()) - .append(time.getSecond() < 10 ? ":0" : ":") - .append(time.getSecond()); + .append(time.getHour() < 10 ? "0" : "") + .append(time.getHour()) + .append(time.getMinute() < 10 ? ":0" : ":") + .append(time.getMinute()) + .append(time.getSecond() < 10 ? ":0" : ":") + .append(time.getSecond()); int microseconds = time.getNano() / 1000; if (microseconds > 0 && fractionalSeconds) { dateString.append("."); @@ -85,7 +83,6 @@ public long getApproximateTextProtocolLength() { * @param pos socket output stream * @throws IOException if socket error occur */ - public void writeBinary(final PacketOutputStream pos) throws IOException { int nano = time.getNano(); if (fractionalSeconds && nano > 0) { @@ -97,7 +94,7 @@ public void writeBinary(final PacketOutputStream pos) throws IOException { pos.write((byte) time.getSecond()); pos.writeInt(nano / 1000); } else { - pos.write((byte) 8);//length + pos.write((byte) 8); // length pos.write((byte) 0); pos.writeInt(0); pos.write((byte) time.getHour()); @@ -122,4 +119,4 @@ public boolean isNullData() { public boolean isLongData() { return false; } -} \ No newline at end of file +} diff --git a/src/main/java/org/mariadb/jdbc/internal/util/DefaultOptions.java b/src/main/java/org/mariadb/jdbc/internal/util/DefaultOptions.java index 8ff7bc344..ee3664f2e 100755 --- a/src/main/java/org/mariadb/jdbc/internal/util/DefaultOptions.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/DefaultOptions.java @@ -3,7 +3,7 @@ * MariaDB Client for Java * * Copyright (c) 2012-2014 Monty Program Ab. - * Copyright (c) 2015-2017 MariaDB Ab. + * Copyright (c) 2015-2019 MariaDB Ab. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free diff --git a/src/main/java/org/mariadb/jdbc/internal/util/Options.java b/src/main/java/org/mariadb/jdbc/internal/util/Options.java index 6099eaa4a..f931fd7ac 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/Options.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/Options.java @@ -3,7 +3,7 @@ * MariaDB Client for Java * * Copyright (c) 2012-2014 Monty Program Ab. - * Copyright (c) 2015-2017 MariaDB Ab. + * Copyright (c) 2015-2019 MariaDB Ab. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free diff --git a/src/main/java/org/mariadb/jdbc/internal/util/Utils.java b/src/main/java/org/mariadb/jdbc/internal/util/Utils.java index d5fa69809..46fe216fe 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/Utils.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/Utils.java @@ -86,14 +86,16 @@ public class Utils { private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); - private static final Pattern IP_V4 = Pattern - .compile("^(([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){1}" - + "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){2}" - + "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"); + private static final Pattern IP_V4 = + Pattern.compile( + "^(([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){1}" + + "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){2}" + + "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"); private static final Pattern IP_V6 = Pattern.compile("^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$"); - private static final Pattern IP_V6_COMPRESSED = Pattern - .compile("^(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)" - + "::(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); + private static final Pattern IP_V6_COMPRESSED = + Pattern.compile( + "^(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)" + + "::(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); private static final SocketHandlerFunction socketHandler; @@ -102,8 +104,8 @@ public class Utils { try { init = SocketUtility.getSocketHandler(); } catch (Throwable t) { - SocketHandlerFunction defaultSocketHandler = (urlParser, host) -> Utils - .standardSocket(urlParser, host); + SocketHandlerFunction defaultSocketHandler = + (urlParser, host) -> Utils.standardSocket(urlParser, host); init = defaultSocketHandler; } socketHandler = init; @@ -113,7 +115,7 @@ public class Utils { * Use standard socket implementation. * * @param urlParser url parser - * @param host host to connect + * @param host host to connect * @return socket * @throws IOException in case of error establishing socket. */ @@ -123,8 +125,8 @@ public static Socket standardSocket(UrlParser urlParser, String host) throws IOE if (socketFactoryName != null) { try { @SuppressWarnings("unchecked") - Class socketFactoryClass = (Class) Class - .forName(socketFactoryName); + Class socketFactoryClass = + (Class) Class.forName(socketFactoryName); if (socketFactoryClass != null) { Constructor constructor = socketFactoryClass.getConstructor(); socketFactory = constructor.newInstance(); @@ -133,7 +135,9 @@ public static Socket standardSocket(UrlParser urlParser, String host) throws IOE } catch (Exception exp) { throw new IOException( "Socket factory failed to initialized with option \"socketFactory\" set to \"" - + urlParser.getOptions().socketFactory + "\"", exp); + + urlParser.getOptions().socketFactory + + "\"", + exp); } } socketFactory = SocketFactory.getDefault(); @@ -143,7 +147,7 @@ public static Socket standardSocket(UrlParser urlParser, String host) throws IOE /** * Escape String. * - * @param value value to escape + * @param value value to escape * @param noBackslashEscapes must backslash be escaped * @return escaped string. */ @@ -166,21 +170,21 @@ public static String escapeString(String value, boolean noBackslashEscapes) { /** * Encrypts a password. * - *

      protocol for authentication is like this: 1. Server sends a random array of bytes (the - * seed) 2. client makes a sha1 digest of the password 3. client hashes the output of 2 4. client + *

      protocol for authentication is like this: 1. Server sends a random array of bytes (the seed) + * 2. client makes a sha1 digest of the password 3. client hashes the output of 2 4. client * digests the seed 5. client updates the digest with the output from 3 6. an xor of the output of * 5 and 2 is sent to server 7. server does the same thing and verifies that the scrambled - * passwords match

      + * passwords match * - * @param password the password to encrypt - * @param seed the seed to use + * @param password the password to encrypt + * @param seed the seed to use * @param passwordCharacterEncoding password character encoding * @return a scrambled password - * @throws NoSuchAlgorithmException if SHA1 is not available on the platform we are using + * @throws NoSuchAlgorithmException if SHA1 is not available on the platform we are using * @throws UnsupportedEncodingException if passwordCharacterEncoding is not a valid charset name */ - public static byte[] encryptPassword(final String password, final byte[] seed, - String passwordCharacterEncoding) + public static byte[] encryptPassword( + final String password, final byte[] seed, String passwordCharacterEncoding) throws NoSuchAlgorithmException, UnsupportedEncodingException { if (password == null || password.isEmpty()) { @@ -218,7 +222,7 @@ public static byte[] encryptPassword(final String password, final byte[] seed, * truncated. If length is bigger than the original byte array, the resulting byte array is filled * with zero bytes. * - * @param orig the original byte array + * @param orig the original byte array * @param length how big the resulting byte array will be * @return the copied byte array */ @@ -236,8 +240,8 @@ public static byte[] copyWithLength(byte[] orig, int length) { * * @param orig the original byte array * @param from index of first byte in original byte array which will be copied - * @param to index of last byte in original byte array which will be copied. This can be outside - * of the original byte array + * @param to index of last byte in original byte array which will be copied. This can be outside + * of the original byte array * @return resulting array */ public static byte[] copyRange(byte[] orig, int from, int to) { @@ -249,15 +253,19 @@ public static byte[] copyRange(byte[] orig, int from, int to) { } /** - * Helper function to replace function parameters in escaped string. - * 3 functions are handles : + * Helper function to replace function parameters in escaped string. 3 functions are handles : + * *
        - *
      • CONVERT(value, type): replacing SQL_XXX types to convertible type, i.e SQL_BIGINT to INTEGER
      • - *
      • TIMESTAMPDIFF(type, ...): replacing type SQL_TSI_XXX in type with XXX, i.e SQL_TSI_HOUR with HOUR
      • - *
      • TIMESTAMPADD(type, ...): replacing type SQL_TSI_XXX in type with XXX, i.e SQL_TSI_HOUR with HOUR
      • + *
      • CONVERT(value, type): replacing SQL_XXX types to convertible type, i.e SQL_BIGINT to + * INTEGER + *
      • TIMESTAMPDIFF(type, ...): replacing type SQL_TSI_XXX in type with XXX, i.e SQL_TSI_HOUR + * with HOUR + *
      • TIMESTAMPADD(type, ...): replacing type SQL_TSI_XXX in type with XXX, i.e SQL_TSI_HOUR + * with HOUR *
      - * caution: this use MariaDB server conversion: 'SELECT CONVERT('2147483648', INTEGER)' will return a BIGINT. - * MySQL will throw a syntax error. + * + *

      caution: this use MariaDB server conversion: 'SELECT CONVERT('2147483648', INTEGER)' will + * return a BIGINT. MySQL will throw a syntax error.

      * * @param functionString - input string * @return unescaped string @@ -273,8 +281,10 @@ private static String replaceFunctionParameter(String functionString) { } } - for (; ((input[index] >= 'a' && index <= 'z') || (input[index] >= 'A' && input[index] <= 'Z')) - && index < input.length; index++) { + for (; + ((input[index] >= 'a' && index <= 'z') || (input[index] >= 'A' && input[index] <= 'Z')) + && index < input.length; + index++) { sb.append(input[index]); } String func = sb.toString().toLowerCase(Locale.ROOT); @@ -292,12 +302,16 @@ private static String replaceFunctionParameter(String functionString) { int endParam = index + 1; for (; endParam < input.length; endParam++) { - if ((input[endParam] < 'a' || input[endParam] > 'z') && (input[endParam] < 'A' || input[endParam] > 'Z') && input[endParam] != '_'){ + if ((input[endParam] < 'a' || input[endParam] > 'z') + && (input[endParam] < 'A' || input[endParam] > 'Z') + && input[endParam] != '_') { break; } } String typeParam = new String(input, index, endParam - index).toUpperCase(Locale.ROOT); - if (typeParam.startsWith("SQL_")) typeParam = typeParam.substring(4); + if (typeParam.startsWith("SQL_")) { + typeParam = typeParam.substring(4); + } switch (typeParam) { case "BIGINT": @@ -340,8 +354,13 @@ private static String replaceFunctionParameter(String functionString) { case "TIMESTAMP": typeParam = "DATETIME"; break; + + default: + break; } - return new String(input, 0, index) + typeParam + new String(input, endParam, input.length - endParam); + return new String(input, 0, index) + + typeParam + + new String(input, endParam, input.length - endParam); case "timestampdiff": case "timestampadd": @@ -354,15 +373,15 @@ private static String replaceFunctionParameter(String functionString) { if (index < input.length - 8) { String paramPrefix = new String(input, index, 8); if ("SQL_TSI_".equals(paramPrefix)) { - return new String(input, 0, index) + new String(input, index + 8,input.length - (index + 8)); + return new String(input, 0, index) + + new String(input, index + 8, input.length - (index + 8)); } } + return functionString; default: return functionString; } - - } private static String resolveEscapes(String escaped, boolean noBackslashEscapes) @@ -386,7 +405,7 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) // time literal return escaped.substring(3, endIndex); } else if (escaped.startsWith("{ts ")) { - //timestamp literal + // timestamp literal return escaped.substring(4, endIndex); } else if (escaped.startsWith("{d'")) { // date literal, no space @@ -395,10 +414,11 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) // time literal return escaped.substring(2, endIndex); } else if (escaped.startsWith("{ts'")) { - //timestamp literal + // timestamp literal return escaped.substring(3, endIndex); } else if (escaped.startsWith("{call ") || escaped.startsWith("{CALL ")) { - // We support uppercase "{CALL" only because Connector/J supports it. It is not in the JDBC spec. + // We support uppercase "{CALL" only because Connector/J supports it. It is not in the JDBC + // spec. return nativeSql(escaped.substring(1, endIndex), noBackslashEscapes); } else if (escaped.startsWith("{escape ")) { @@ -407,7 +427,8 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) // likely ?=call(...) return nativeSql(escaped.substring(1, endIndex), noBackslashEscapes); } else if (escaped.startsWith("{ ") || escaped.startsWith("{\n")) { - // Spaces and newlines before keyword, this is not JDBC compliant, however some it works in some drivers, + // Spaces and newlines before keyword, this is not JDBC compliant, however some it works in + // some drivers, // so we support it, too for (int i = 2; i < escaped.length(); i++) { if (!Character.isWhitespace(escaped.charAt(i))) { @@ -415,7 +436,8 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) } } } else if (escaped.startsWith("{\r\n")) { - // Spaces and newlines before keyword, this is not JDBC compliant, however some it works in some drivers, + // Spaces and newlines before keyword, this is not JDBC compliant, however some it works in + // some drivers, // so we support it, too for (int i = 3; i < escaped.length(); i++) { if (!Character.isWhitespace(escaped.charAt(i))) { @@ -429,7 +451,7 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) /** * Escape sql String. * - * @param sql initial sql + * @param sql initial sql * @param noBackslashEscapes must backslash be escape * @return escaped sql string * @throws SQLException if escape sequence is incorrect. @@ -526,7 +548,6 @@ public static String nativeSql(String sql, boolean noBackslashEscapes) throws SQ default: break; - } lastChar = car; if (inEscapeSeq > 0) { @@ -547,7 +568,7 @@ public static String nativeSql(String sql, boolean noBackslashEscapes) throws SQ * not be proxied. if a failover option is precised, protocol will be proxied so that any * connection error will be handle directly. * - * @param urlParser urlParser corresponding to connection url string. + * @param urlParser urlParser corresponding to connection url string. * @param globalInfo global variable information * @return protocol * @throws SQLException if any error occur during connection @@ -558,25 +579,33 @@ public static Protocol retrieveProxy(final UrlParser urlParser, final GlobalStat Protocol protocol; switch (urlParser.getHaMode()) { case AURORA: - return getProxyLoggingIfNeeded(urlParser, (Protocol) Proxy.newProxyInstance( - AuroraProtocol.class.getClassLoader(), - new Class[]{Protocol.class}, - new FailoverProxy(new AuroraListener(urlParser, globalInfo), lock))); + return getProxyLoggingIfNeeded( + urlParser, + (Protocol) + Proxy.newProxyInstance( + AuroraProtocol.class.getClassLoader(), + new Class[] {Protocol.class}, + new FailoverProxy(new AuroraListener(urlParser, globalInfo), lock))); case REPLICATION: - return getProxyLoggingIfNeeded(urlParser, - (Protocol) Proxy.newProxyInstance( - MastersSlavesProtocol.class.getClassLoader(), - new Class[]{Protocol.class}, - new FailoverProxy(new MastersSlavesListener(urlParser, globalInfo), lock))); + return getProxyLoggingIfNeeded( + urlParser, + (Protocol) + Proxy.newProxyInstance( + MastersSlavesProtocol.class.getClassLoader(), + new Class[] {Protocol.class}, + new FailoverProxy(new MastersSlavesListener(urlParser, globalInfo), lock))); case LOADBALANCE: case SEQUENTIAL: - return getProxyLoggingIfNeeded(urlParser, (Protocol) Proxy.newProxyInstance( - MasterProtocol.class.getClassLoader(), - new Class[]{Protocol.class}, - new FailoverProxy(new MastersFailoverListener(urlParser, globalInfo), lock))); + return getProxyLoggingIfNeeded( + urlParser, + (Protocol) + Proxy.newProxyInstance( + MasterProtocol.class.getClassLoader(), + new Class[] {Protocol.class}, + new FailoverProxy(new MastersFailoverListener(urlParser, globalInfo), lock))); default: - protocol = getProxyLoggingIfNeeded(urlParser, - new MasterProtocol(urlParser, globalInfo, lock)); + protocol = + getProxyLoggingIfNeeded(urlParser, new MasterProtocol(urlParser, globalInfo, lock)); protocol.connectWithoutProxy(); return protocol; } @@ -585,10 +614,11 @@ public static Protocol retrieveProxy(final UrlParser urlParser, final GlobalStat private static Protocol getProxyLoggingIfNeeded(UrlParser urlParser, Protocol protocol) { if (urlParser.getOptions().profileSql || urlParser.getOptions().slowQueryThresholdNanos != null) { - return (Protocol) Proxy.newProxyInstance( - MasterProtocol.class.getClassLoader(), - new Class[]{Protocol.class}, - new ProtocolLoggingProxy(protocol, urlParser.getOptions())); + return (Protocol) + Proxy.newProxyInstance( + MasterProtocol.class.getClassLoader(), + new Class[] {Protocol.class}, + new ProtocolLoggingProxy(protocol, urlParser.getOptions())); } return protocol; } @@ -615,7 +645,7 @@ public static TimeZone getTimeZone(String id) throws SQLException { * Create socket accordingly to options. * * @param urlParser urlParser - * @param host hostName ( mandatory only for named pipe) + * @param host hostName ( mandatory only for named pipe) * @return a nex socket * @throws IOException if connection error occur */ @@ -636,31 +666,30 @@ public static String hexdump(byte[]... bytes) { /** * Hexdump. * - *

      String output example :

      - *
      -   * {@code
      -   *    7D 00 00 01 C5 00 00                                 }......            <- first byte array
      -   *    01 00 00 01 02 33 00 00  02 03 64 65 66 05 74 65     .....3....def.te   <- second byte array
      -   *    73 74 6A 0A 74 65 73 74  5F 62 61 74 63 68 0A 74     stj.test_batch.t
      -   *    65 73 74 5F 62 61 74 63  68 02 69 64 02 69 64 0C     est_batch.id.id.
      -   *    3F 00 0B 00 00 00 03 03  42 00 00 00 37 00 00 03     ?.......B...7...
      -   *    03 64 65 66 05 74 65 73  74 6A 0A 74 65 73 74 5F     .def.testj.test_
      -   *    62 61 74 63 68 0A 74 65  73 74 5F 62 61 74 63 68     batch.test_batch
      -   *    04 74 65 73 74 04 74 65  73 74 0C 21 00 1E 00 00     .test.test.!....
      -   *    00 FD 00 00 00 00 00 05  00 00 04 FE 00 00 22 00     ..............".
      -   *    06 00 00 05 01 31 03 61  61 61 06 00 00 06 01 32     .....1.aaa.....2
      -   *    03 62 62 62 06 00 00 07  01 33 03 63 63 63 06 00     .bbb.....3.ccc..
      -   *    00 08 01 34 03 61 61 61  06 00 00 09 01 35 03 62     ...4.aaa.....5.b
      -   *    62 62 06 00 00 0A 01 36  03 63 63 63 05 00 00 0B     bb.....6.ccc....
      -   *    FE 00 00 22 00                                       ...".
      -   * }
      -   * 
      + *

      String output example : + * + *

      {@code
      +   * 7D 00 00 01 C5 00 00                                 }......            <- first byte array
      +   * 01 00 00 01 02 33 00 00  02 03 64 65 66 05 74 65     .....3....def.te   <- second byte array
      +   * 73 74 6A 0A 74 65 73 74  5F 62 61 74 63 68 0A 74     stj.test_batch.t
      +   * 65 73 74 5F 62 61 74 63  68 02 69 64 02 69 64 0C     est_batch.id.id.
      +   * 3F 00 0B 00 00 00 03 03  42 00 00 00 37 00 00 03     ?.......B...7...
      +   * 03 64 65 66 05 74 65 73  74 6A 0A 74 65 73 74 5F     .def.testj.test_
      +   * 62 61 74 63 68 0A 74 65  73 74 5F 62 61 74 63 68     batch.test_batch
      +   * 04 74 65 73 74 04 74 65  73 74 0C 21 00 1E 00 00     .test.test.!....
      +   * 00 FD 00 00 00 00 00 05  00 00 04 FE 00 00 22 00     ..............".
      +   * 06 00 00 05 01 31 03 61  61 61 06 00 00 06 01 32     .....1.aaa.....2
      +   * 03 62 62 62 06 00 00 07  01 33 03 63 63 63 06 00     .bbb.....3.ccc..
      +   * 00 08 01 34 03 61 61 61  06 00 00 09 01 35 03 62     ...4.aaa.....5.b
      +   * 62 62 06 00 00 0A 01 36  03 63 63 63 05 00 00 0B     bb.....6.ccc....
      +   * FE 00 00 22 00                                       ...".
      +   * }
      * * @param maxQuerySizeToLog max log size - * @param offset offset of last byte array - * @param length length of last byte array - * @param byteArr byte arrays. if many, only the last may have offset and size - * limitation others will be displayed completely. + * @param offset offset of last byte array + * @param length length of last byte array + * @param byteArr byte arrays. if many, only the last may have offset and size limitation others + * will be displayed completely. * @return String */ public static String hexdump(int maxQuerySizeToLog, int offset, int length, byte[]... byteArr) { @@ -692,7 +721,6 @@ public static String hexdump(int maxQuerySizeToLog, int offset, int length, byte int dataLength2 = Math.min(maxQuerySizeToLog, Math.min(arr.length - offset, length)); writeHex(arr, offset, dataLength2, sb); return sb.toString(); - } } @@ -700,22 +728,21 @@ public static String hexdump(int maxQuerySizeToLog, int offset, int length, byte * Write bytes/hexadecimal value of a byte array to a StringBuilder. * *

      String output example : - *

      -   * {@code
      +   *
      +   * 
      {@code
          * 38 00 00 00 03 63 72 65  61 74 65 20 74 61 62 6C     8....create tabl
          * 65 20 42 6C 6F 62 54 65  73 74 63 6C 6F 62 74 65     e BlobTestclobte
          * 73 74 32 20 28 73 74 72  6D 20 74 65 78 74 29 20     st2 (strm text)
          * 43 48 41 52 53 45 54 20  75 74 66 38                 CHARSET utf8
      -   * }
      -   * 

      + * }
      * - * @param bytes byte array - * @param offset offset - * @param dataLength byte length to write + * @param bytes byte array + * @param offset offset + * @param dataLength byte length to write * @param outputBuilder string builder */ - private static void writeHex(byte[] bytes, int offset, int dataLength, - StringBuilder outputBuilder) { + private static void writeHex( + byte[] bytes, int offset, int dataLength, StringBuilder outputBuilder) { if (bytes == null || bytes.length == 0) { return; @@ -729,7 +756,8 @@ private static void writeHex(byte[] bytes, int offset, int dataLength, while (pos < dataLength + offset) { int byteValue = bytes[pos] & 0xFF; - outputBuilder.append(hexArray[byteValue >>> 4]) + outputBuilder + .append(hexArray[byteValue >>> 4]) .append(hexArray[byteValue & 0x0F]) .append(" "); @@ -739,9 +767,7 @@ private static void writeHex(byte[] bytes, int offset, int dataLength, outputBuilder.append(" "); } if (posHexa == 16) { - outputBuilder.append(" ") - .append(hexaValue) - .append("\n"); + outputBuilder.append(" ").append(hexaValue).append("\n"); posHexa = 0; } pos++; @@ -760,17 +786,14 @@ private static void writeHex(byte[] bytes, int offset, int dataLength, outputBuilder.append(" "); } - outputBuilder.append(" ") - .append(hexaValue, 0, posHexa) - .append("\n"); + outputBuilder.append(" ").append(hexaValue, 0, posHexa).append("\n"); } } private static String getHex(final byte[] raw) { final StringBuilder hex = new StringBuilder(2 * raw.length); for (final byte b : raw) { - hex.append(hexArray[(b & 0xF0) >> 4]) - .append(hexArray[(b & 0x0F)]); + hex.append(hexArray[(b & 0xF0) >> 4]).append(hexArray[(b & 0x0F)]); } return hex.toString(); } @@ -795,8 +818,7 @@ public static String intToHexString(final int value) { offset -= 8; if (b != 0 || nullEnd) { nullEnd = true; - hex.append(hexArray[(b & 0xF0) >> 4]) - .append(hexArray[(b & 0x0F)]); + hex.append(hexArray[(b & 0xF0) >> 4]).append(hexArray[(b & 0x0F)]); } } return hex.toString(); @@ -889,7 +911,7 @@ public static String parseSessionVariables(String sessionVariable) { break; default: - //nothing + // nothing } sb.append(car); @@ -926,11 +948,11 @@ public static boolean isIPv6(final String ip) { * @return java corresponding value (Connection.TRANSACTION_READ_UNCOMMITTED, * Connection.TRANSACTION_READ_COMMITTED, Connection.TRANSACTION_REPEATABLE_READ or * Connection.TRANSACTION_SERIALIZABLE) - * @throws SQLException if String value doesn't correspond to @@tx_isolation/@@transaction_isolation - * possible value + * @throws SQLException if String value doesn't correspond + * to @@tx_isolation/@@transaction_isolation possible value */ public static int transactionFromString(String txIsolation) throws SQLException { - switch (txIsolation) { //tx_isolation + switch (txIsolation) { // tx_isolation case "READ-UNCOMMITTED": return Connection.TRANSACTION_READ_UNCOMMITTED; @@ -958,23 +980,28 @@ private enum Parse { /** * Validate that file name correspond to send query. * - * @param sql sql command - * @param parameters sql parameter - * @param fileName server file name + * @param sql sql command + * @param parameters sql parameter + * @param fileName server file name * @return true if correspond */ - public static boolean validateFileName(String sql, ParameterHolder[] parameters, String fileName) { - Pattern pattern = Pattern.compile( - "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+'" + fileName + "'", - Pattern.CASE_INSENSITIVE); + public static boolean validateFileName( + String sql, ParameterHolder[] parameters, String fileName) { + Pattern pattern = + Pattern.compile( + "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+'" + + fileName + + "'", + Pattern.CASE_INSENSITIVE); if (pattern.matcher(sql).find()) { return true; } if (parameters != null) { - pattern = Pattern.compile( - "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+\\?", - Pattern.CASE_INSENSITIVE); + pattern = + Pattern.compile( + "^(\\s*\\/\\*([^\\*]|\\*[^\\/])*\\*\\/)*\\s*LOAD\\s+DATA\\s+((LOW_PRIORITY|CONCURRENT)\\s+)?LOCAL\\s+INFILE\\s+\\?", + Pattern.CASE_INSENSITIVE); if (pattern.matcher(sql).find() && parameters.length > 0) { return parameters[0].toString().toLowerCase().equals("'" + fileName.toLowerCase() + "'"); } diff --git a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java index eeabbc5f1..b9850c37d 100644 --- a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java @@ -4,177 +4,193 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import org.junit.Test; -import java.sql.*; -import java.time.*; - public class LocalTimeTest extends BaseTest { - @Test - public void LocalTimeTest() throws SQLException { - Statement stmt = sharedConnection.createStatement(); - stmt.execute("CREATE TEMPORARY TABLE LocalTimeTest(val TIME(6), val2 TIME)"); - try (PreparedStatement prep = sharedConnection.prepareStatement("INSERT INTO LocalTimeTest value (?, ?)")) { - prep.setObject(1, LocalTime.of(1, 2, 3, 123456789)); - prep.setObject(2, LocalTime.of(2, 3, 4, 120000000)); - prep.execute(); - - prep.setObject(1, LocalTime.of(15, 14, 13, 12340000)); - prep.setObject(2, LocalTime.of(16, 15, 14, 12340000)); - prep.execute(); - - prep.setObject(1, LocalTime.of(5, 4, 3, 0)); - prep.setObject(2, LocalTime.of(6, 5, 4, 0)); - prep.execute(); - } - ResultSet rs = stmt.executeQuery("SELECT * FROM LocalTimeTest"); - assertTrue(rs.next()); - - assertEquals("01:02:03.123456", rs.getString(1)); - assertEquals(LocalTime.of(1, 2, 3, 123456000), rs.getObject(1, LocalTime.class)); - assertEquals("01:02:03", rs.getTime(1).toString()); - assertEquals(Time.valueOf("01:02:03").getTime() + 123 , rs.getTime(1).getTime()); - - assertEquals("02:03:04", rs.getString(2)); - assertEquals(LocalTime.of(2, 3, 4, 0), rs.getObject(2, LocalTime.class)); - assertEquals(Time.valueOf("02:03:04"), rs.getTime(2)); - assertEquals(Time.valueOf("02:03:04").getTime() , rs.getTime(2).getTime()); - - assertTrue(rs.next()); - - assertEquals("15:14:13.012340", rs.getString(1)); - assertEquals(LocalTime.of(15, 14, 13, 12340000), rs.getObject(1, LocalTime.class)); - assertEquals(Time.valueOf("15:14:13").toString(), rs.getTime(1).toString()); - assertEquals(Time.valueOf("15:14:13").getTime() + 12, rs.getTime(1).getTime()); - - assertEquals("16:15:14", rs.getString(2)); - assertEquals(LocalTime.of(16, 15, 14, 0), rs.getObject(2, LocalTime.class)); - assertEquals(Time.valueOf("16:15:14").toString(), rs.getTime(2).toString()); - assertEquals(Time.valueOf("16:15:14").getTime(), rs.getTime(2).getTime()); - - assertTrue(rs.next()); - - assertEquals("05:04:03.000000", rs.getString(1)); - assertEquals(LocalTime.of(5, 4, 3, 0), rs.getObject(1, LocalTime.class)); - assertEquals(Time.valueOf("05:04:03").toString(), rs.getTime(1).toString()); - assertEquals(Time.valueOf("05:04:03").getTime(), rs.getTime(1).getTime()); - - assertEquals("06:05:04", rs.getString(2)); - assertEquals(LocalTime.of(6, 5, 4, 0), rs.getObject(2, LocalTime.class)); - assertEquals(Time.valueOf("06:05:04").toString(), rs.getTime(2).toString()); - assertEquals(Time.valueOf("06:05:04").getTime(), rs.getTime(2).getTime()); - - assertFalse(rs.next()); + @Test + public void localTimeTest() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("CREATE TEMPORARY TABLE LocalTimeTest(val TIME(6), val2 TIME)"); + try (PreparedStatement prep = + sharedConnection.prepareStatement("INSERT INTO LocalTimeTest value (?, ?)")) { + prep.setObject(1, LocalTime.of(1, 2, 3, 123456789)); + prep.setObject(2, LocalTime.of(2, 3, 4, 120000000)); + prep.execute(); + + prep.setObject(1, LocalTime.of(15, 14, 13, 12340000)); + prep.setObject(2, LocalTime.of(16, 15, 14, 12340000)); + prep.execute(); + + prep.setObject(1, LocalTime.of(5, 4, 3, 0)); + prep.setObject(2, LocalTime.of(6, 5, 4, 0)); + prep.execute(); } - - - @Test - public void LocalDateTest() throws SQLException { - Statement stmt = sharedConnection.createStatement(); - stmt.execute("CREATE TEMPORARY TABLE LocalDateTest(val DATE)"); - try (PreparedStatement prep = sharedConnection.prepareStatement("INSERT INTO LocalDateTest value (?)")) { - prep.setObject(1, LocalDate.of(2000, 12, 31)); - prep.execute(); - prep.setObject(1, LocalDate.of(1000, 1, 1)); - prep.execute(); - prep.setObject(1, LocalDate.of(9999, 1, 31)); - prep.execute(); - } - ResultSet rs = stmt.executeQuery("SELECT * FROM LocalDateTest"); - assertTrue(rs.next()); - - assertEquals("2000-12-31", rs.getString(1)); - assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(1, LocalDate.class)); - - assertTrue(rs.next()); - assertEquals("1000-01-01", rs.getString(1)); - assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(1, LocalDate.class)); - - assertTrue(rs.next()); - assertEquals("9999-01-31", rs.getString(1)); - assertEquals(LocalDate.of(9999, 1, 31), rs.getObject(1, LocalDate.class)); - assertFalse(rs.next()); + ResultSet rs = stmt.executeQuery("SELECT * FROM LocalTimeTest"); + assertTrue(rs.next()); + + assertEquals("01:02:03.123456", rs.getString(1)); + assertEquals(LocalTime.of(1, 2, 3, 123456000), rs.getObject(1, LocalTime.class)); + assertEquals("01:02:03", rs.getTime(1).toString()); + assertEquals(Time.valueOf("01:02:03").getTime() + 123, rs.getTime(1).getTime()); + + assertEquals("02:03:04", rs.getString(2)); + assertEquals(LocalTime.of(2, 3, 4, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("02:03:04"), rs.getTime(2)); + assertEquals(Time.valueOf("02:03:04").getTime(), rs.getTime(2).getTime()); + + assertTrue(rs.next()); + + assertEquals("15:14:13.012340", rs.getString(1)); + assertEquals(LocalTime.of(15, 14, 13, 12340000), rs.getObject(1, LocalTime.class)); + assertEquals(Time.valueOf("15:14:13").toString(), rs.getTime(1).toString()); + assertEquals(Time.valueOf("15:14:13").getTime() + 12, rs.getTime(1).getTime()); + + assertEquals("16:15:14", rs.getString(2)); + assertEquals(LocalTime.of(16, 15, 14, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("16:15:14").toString(), rs.getTime(2).toString()); + assertEquals(Time.valueOf("16:15:14").getTime(), rs.getTime(2).getTime()); + + assertTrue(rs.next()); + + assertEquals("05:04:03.000000", rs.getString(1)); + assertEquals(LocalTime.of(5, 4, 3, 0), rs.getObject(1, LocalTime.class)); + assertEquals(Time.valueOf("05:04:03").toString(), rs.getTime(1).toString()); + assertEquals(Time.valueOf("05:04:03").getTime(), rs.getTime(1).getTime()); + + assertEquals("06:05:04", rs.getString(2)); + assertEquals(LocalTime.of(6, 5, 4, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("06:05:04").toString(), rs.getTime(2).toString()); + assertEquals(Time.valueOf("06:05:04").getTime(), rs.getTime(2).getTime()); + + assertFalse(rs.next()); + } + + @Test + public void localDateTest() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("CREATE TEMPORARY TABLE LocalDateTest(val DATE)"); + try (PreparedStatement prep = + sharedConnection.prepareStatement("INSERT INTO LocalDateTest value (?)")) { + prep.setObject(1, LocalDate.of(2000, 12, 31)); + prep.execute(); + prep.setObject(1, LocalDate.of(1000, 1, 1)); + prep.execute(); + prep.setObject(1, LocalDate.of(9999, 1, 31)); + prep.execute(); } - - @Test - public void LocalDateTimeTest() throws SQLException { - Statement stmt = sharedConnection.createStatement(); - stmt.execute("CREATE TEMPORARY TABLE LocalDateTimeTest(val DATETIME(6), val2 DATETIME)"); - try (PreparedStatement prep = sharedConnection.prepareStatement("INSERT INTO LocalDateTimeTest value (?, ?)")) { - prep.setObject(1, LocalDateTime.of(2000, 12, 31,1, 2, 3, 123456789)); - prep.setObject(2, LocalDateTime.of(2000, 12, 31,2, 3, 4, 120000000)); - prep.execute(); - - prep.setObject(1, LocalDateTime.of(1000, 1, 1,15, 14, 13, 12340000)); - prep.setObject(2, LocalDateTime.of(1000, 1, 1,16, 15, 14, 12340000)); - prep.execute(); - - prep.setObject(1, LocalDateTime.of(9999, 12, 31,5, 4, 3, 0)); - prep.setObject(2, LocalDateTime.of(9999, 12, 31,6, 5, 4, 0)); - prep.execute(); - } - ResultSet rs = stmt.executeQuery("SELECT * FROM LocalDateTimeTest"); - assertTrue(rs.next()); - - assertEquals("2000-12-31 01:02:03.123456", rs.getString(1)); - assertEquals(LocalDateTime.of(2000, 12, 31,1, 2, 3, 123456000), rs.getObject(1, LocalDateTime.class)); - assertEquals("2000-12-31 01:02:03.123456", rs.getTimestamp(1).toString()); - assertEquals(Timestamp.valueOf("2000-12-31 01:02:03").getTime() + 123 , rs.getTimestamp(1).getTime()); - assertEquals(LocalTime.of(1, 2, 3, 123456000), rs.getObject(1, LocalTime.class)); - assertEquals("01:02:03", rs.getTime(1).toString()); - assertEquals(Timestamp.valueOf("2000-12-31 01:02:03").getTime() + 123 , rs.getTime(1).getTime()); - assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(1, LocalDate.class)); - - assertEquals("2000-12-31 02:03:04.0", rs.getString(2)); - assertEquals(LocalDateTime.of(2000, 12, 31,2, 3, 4, 0), rs.getObject(2, LocalDateTime.class)); - assertEquals(Timestamp.valueOf("2000-12-31 02:03:04"), rs.getTimestamp(2)); - assertEquals(Timestamp.valueOf("2000-12-31 02:03:04").getTime() , rs.getTimestamp(2).getTime()); - assertEquals(LocalTime.of(2, 3, 4, 0), rs.getObject(2, LocalTime.class)); - assertEquals(Time.valueOf("02:03:04").toString(), rs.getTime(2).toString()); - assertEquals(Timestamp.valueOf("2000-12-31 02:03:04").getTime() , rs.getTime(2).getTime()); - assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(2, LocalDate.class)); - - assertTrue(rs.next()); - - assertEquals("1000-01-01 15:14:13.01234", rs.getString(1)); - assertEquals(LocalDateTime.of(1000, 1, 1,15, 14, 13, 12340000), rs.getObject(1, LocalDateTime.class)); - assertEquals(Timestamp.valueOf("1000-01-01 15:14:13.01234").toString(), rs.getTimestamp(1).toString()); - assertEquals(Timestamp.valueOf("1000-01-01 15:14:13").getTime() + 12, rs.getTimestamp(1).getTime()); - assertEquals(LocalTime.of(15, 14, 13, 12340000), rs.getObject(1, LocalTime.class)); - assertEquals(Time.valueOf("15:14:13").toString(), rs.getTime(1).toString()); - assertEquals(Timestamp.valueOf("1000-01-01 15:14:13.01234").getTime(), rs.getTime(1).getTime()); - assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(1, LocalDate.class)); - - assertEquals("1000-01-01 16:15:14.0", rs.getString(2)); - assertEquals(LocalDateTime.of(1000, 1, 1,16, 15, 14, 0), rs.getObject(2, LocalDateTime.class)); - assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").toString(), rs.getTimestamp(2).toString()); - assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").getTime(), rs.getTimestamp(2).getTime()); - assertEquals(LocalTime.of(16, 15, 14, 0), rs.getObject(2, LocalTime.class)); - assertEquals(Time.valueOf("16:15:14").toString(), rs.getTime(2).toString()); - assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").getTime(), rs.getTime(2).getTime()); - assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(2, LocalDate.class)); - - assertTrue(rs.next()); - - assertEquals("9999-12-31 05:04:03.0", rs.getString(1)); - assertEquals(LocalDateTime.of(9999, 12, 31, 5, 4, 3, 0), rs.getObject(1, LocalDateTime.class)); - assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").toString(), rs.getTimestamp(1).toString()); - assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").getTime(), rs.getTimestamp(1).getTime()); - assertEquals(LocalTime.of(5, 4, 3, 0), rs.getObject(1, LocalTime.class)); - assertEquals(Time.valueOf("05:04:03").toString(), rs.getTime(1).toString()); - assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").getTime(), rs.getTime(1).getTime()); - assertEquals(LocalDate.of(9999, 12, 31), rs.getObject(1, LocalDate.class)); - - assertEquals("9999-12-31 06:05:04.0", rs.getString(2)); - assertEquals(LocalDateTime.of(9999, 12, 31, 6, 5, 4, 0), rs.getObject(2, LocalDateTime.class)); - assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").toString(), rs.getTimestamp(2).toString()); - assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").getTime(), rs.getTimestamp(2).getTime()); - assertEquals(LocalTime.of(6, 5, 4, 0), rs.getObject(2, LocalTime.class)); - assertEquals(Time.valueOf("06:05:04").toString(), rs.getTime(2).toString()); - assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").getTime(), rs.getTime(2).getTime()); - assertEquals(LocalDate.of(9999, 12, 31), rs.getObject(1, LocalDate.class)); - - assertFalse(rs.next()); + ResultSet rs = stmt.executeQuery("SELECT * FROM LocalDateTest"); + assertTrue(rs.next()); + + assertEquals("2000-12-31", rs.getString(1)); + assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(1, LocalDate.class)); + + assertTrue(rs.next()); + assertEquals("1000-01-01", rs.getString(1)); + assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(1, LocalDate.class)); + + assertTrue(rs.next()); + assertEquals("9999-01-31", rs.getString(1)); + assertEquals(LocalDate.of(9999, 1, 31), rs.getObject(1, LocalDate.class)); + assertFalse(rs.next()); + } + + @Test + public void localDateTimeTest() throws SQLException { + Statement stmt = sharedConnection.createStatement(); + stmt.execute("CREATE TEMPORARY TABLE LocalDateTimeTest(val DATETIME(6), val2 DATETIME)"); + try (PreparedStatement prep = + sharedConnection.prepareStatement("INSERT INTO LocalDateTimeTest value (?, ?)")) { + prep.setObject(1, LocalDateTime.of(2000, 12, 31, 1, 2, 3, 123456789)); + prep.setObject(2, LocalDateTime.of(2000, 12, 31, 2, 3, 4, 120000000)); + prep.execute(); + + prep.setObject(1, LocalDateTime.of(1000, 1, 1, 15, 14, 13, 12340000)); + prep.setObject(2, LocalDateTime.of(1000, 1, 1, 16, 15, 14, 12340000)); + prep.execute(); + + prep.setObject(1, LocalDateTime.of(9999, 12, 31, 5, 4, 3, 0)); + prep.setObject(2, LocalDateTime.of(9999, 12, 31, 6, 5, 4, 0)); + prep.execute(); } + ResultSet rs = stmt.executeQuery("SELECT * FROM LocalDateTimeTest"); + assertTrue(rs.next()); + + assertEquals("2000-12-31 01:02:03.123456", rs.getString(1)); + assertEquals( + LocalDateTime.of(2000, 12, 31, 1, 2, 3, 123456000), rs.getObject(1, LocalDateTime.class)); + assertEquals("2000-12-31 01:02:03.123456", rs.getTimestamp(1).toString()); + assertEquals( + Timestamp.valueOf("2000-12-31 01:02:03").getTime() + 123, rs.getTimestamp(1).getTime()); + assertEquals(LocalTime.of(1, 2, 3, 123456000), rs.getObject(1, LocalTime.class)); + assertEquals("01:02:03", rs.getTime(1).toString()); + assertEquals(Timestamp.valueOf("2000-12-31 01:02:03").getTime() + 123, rs.getTime(1).getTime()); + assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(1, LocalDate.class)); + + assertEquals("2000-12-31 02:03:04.0", rs.getString(2)); + assertEquals(LocalDateTime.of(2000, 12, 31, 2, 3, 4, 0), rs.getObject(2, LocalDateTime.class)); + assertEquals(Timestamp.valueOf("2000-12-31 02:03:04"), rs.getTimestamp(2)); + assertEquals(Timestamp.valueOf("2000-12-31 02:03:04").getTime(), rs.getTimestamp(2).getTime()); + assertEquals(LocalTime.of(2, 3, 4, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("02:03:04").toString(), rs.getTime(2).toString()); + assertEquals(Timestamp.valueOf("2000-12-31 02:03:04").getTime(), rs.getTime(2).getTime()); + assertEquals(LocalDate.of(2000, 12, 31), rs.getObject(2, LocalDate.class)); + + assertTrue(rs.next()); + + assertEquals("1000-01-01 15:14:13.01234", rs.getString(1)); + assertEquals( + LocalDateTime.of(1000, 1, 1, 15, 14, 13, 12340000), rs.getObject(1, LocalDateTime.class)); + assertEquals( + Timestamp.valueOf("1000-01-01 15:14:13.01234").toString(), rs.getTimestamp(1).toString()); + assertEquals( + Timestamp.valueOf("1000-01-01 15:14:13").getTime() + 12, rs.getTimestamp(1).getTime()); + assertEquals(LocalTime.of(15, 14, 13, 12340000), rs.getObject(1, LocalTime.class)); + assertEquals(Time.valueOf("15:14:13").toString(), rs.getTime(1).toString()); + assertEquals(Timestamp.valueOf("1000-01-01 15:14:13.01234").getTime(), rs.getTime(1).getTime()); + assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(1, LocalDate.class)); + + assertEquals("1000-01-01 16:15:14.0", rs.getString(2)); + assertEquals(LocalDateTime.of(1000, 1, 1, 16, 15, 14, 0), rs.getObject(2, LocalDateTime.class)); + assertEquals( + Timestamp.valueOf("1000-01-01 16:15:14").toString(), rs.getTimestamp(2).toString()); + assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").getTime(), rs.getTimestamp(2).getTime()); + assertEquals(LocalTime.of(16, 15, 14, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("16:15:14").toString(), rs.getTime(2).toString()); + assertEquals(Timestamp.valueOf("1000-01-01 16:15:14").getTime(), rs.getTime(2).getTime()); + assertEquals(LocalDate.of(1000, 1, 1), rs.getObject(2, LocalDate.class)); + + assertTrue(rs.next()); + + assertEquals("9999-12-31 05:04:03.0", rs.getString(1)); + assertEquals(LocalDateTime.of(9999, 12, 31, 5, 4, 3, 0), rs.getObject(1, LocalDateTime.class)); + assertEquals( + Timestamp.valueOf("9999-12-31 05:04:03").toString(), rs.getTimestamp(1).toString()); + assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").getTime(), rs.getTimestamp(1).getTime()); + assertEquals(LocalTime.of(5, 4, 3, 0), rs.getObject(1, LocalTime.class)); + assertEquals(Time.valueOf("05:04:03").toString(), rs.getTime(1).toString()); + assertEquals(Timestamp.valueOf("9999-12-31 05:04:03").getTime(), rs.getTime(1).getTime()); + assertEquals(LocalDate.of(9999, 12, 31), rs.getObject(1, LocalDate.class)); + + assertEquals("9999-12-31 06:05:04.0", rs.getString(2)); + assertEquals(LocalDateTime.of(9999, 12, 31, 6, 5, 4, 0), rs.getObject(2, LocalDateTime.class)); + assertEquals( + Timestamp.valueOf("9999-12-31 06:05:04").toString(), rs.getTimestamp(2).toString()); + assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").getTime(), rs.getTimestamp(2).getTime()); + assertEquals(LocalTime.of(6, 5, 4, 0), rs.getObject(2, LocalTime.class)); + assertEquals(Time.valueOf("06:05:04").toString(), rs.getTime(2).toString()); + assertEquals(Timestamp.valueOf("9999-12-31 06:05:04").getTime(), rs.getTime(2).getTime()); + assertEquals(LocalDate.of(9999, 12, 31), rs.getObject(1, LocalDate.class)); + + assertFalse(rs.next()); + } } diff --git a/src/test/java/org/mariadb/jdbc/ResultSetMetaDataTest.java b/src/test/java/org/mariadb/jdbc/ResultSetMetaDataTest.java index 0a274bfd8..9e4a1e197 100644 --- a/src/test/java/org/mariadb/jdbc/ResultSetMetaDataTest.java +++ b/src/test/java/org/mariadb/jdbc/ResultSetMetaDataTest.java @@ -3,7 +3,7 @@ * MariaDB Client for Java * * Copyright (c) 2012-2014 Monty Program Ab. - * Copyright (c) 2015-2017 MariaDB Ab. + * Copyright (c) 2015-2019 MariaDB Ab. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free diff --git a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java index 59026b863..ab14d0291 100644 --- a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java +++ b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java @@ -27,19 +27,21 @@ package org.mariadb.jdbc; -import org.junit.Test; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.math.BigInteger; -import java.sql.*; -import java.util.Arrays; - -import static org.junit.Assert.*; - +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import org.junit.Test; public class ScalarFunctionsTest extends BaseTest { @Test - public void nativeSQLTest() throws SQLException { + public void nativeSqlTest() throws SQLException { assertEquals( "SELECT convert(foo(a,b,c), INTEGER)" + ", convert(convert(?, CHAR), INTEGER)" @@ -101,8 +103,7 @@ public void nativeSQLTest() throws SQLException { + ", {fn convert(?, SQL_REAL)}" + ", {fn convert(?, SQL_NUMERIC)}" + ", {fn convert(?, SQL_TIMESTAMP)}" - + ", {fn convert(?, SQL_DATETIME)}") - ); + + ", {fn convert(?, SQL_DATETIME)}")); } @Test @@ -115,7 +116,10 @@ public void scalarFctTest() throws SQLException { queryScalar("SELECT {fn convert(?, SQL_TINYINT)}", 5000, 5000); queryScalar("SELECT {fn convert(?, SQL_BIT)}", 255, 255); queryScalar("SELECT {fn convert(?, SQL_BINARY)}", "test", "test".getBytes()); - queryScalar("SELECT {fn convert(?, SQL_DATETIME)}", "2020-12-31 12:13.15.12", new Timestamp(2020 - 1900, 11, 31, 12, 13, 15, 0)); + queryScalar( + "SELECT {fn convert(?, SQL_DATETIME)}", + "2020-12-31 12:13.15.12", + new Timestamp(2020 - 1900, 11, 31, 12, 13, 15, 0)); } private void queryScalar(String sql, Object val, Object res) throws SQLException { @@ -125,12 +129,11 @@ private void queryScalar(String sql, Object val, Object res) throws SQLException assertTrue(rs.next()); Object obj = rs.getObject(1); if (obj instanceof byte[]) { - byte[] arr = (byte[]) obj ; + byte[] arr = (byte[]) obj; assertArrayEquals((byte[]) res, arr); } else { assertEquals(res, rs.getObject(1)); } } } - } From fe789ffdad694d55605a363f9003b5e65763ff67 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 2 Aug 2019 09:57:12 +0200 Subject: [PATCH 14/19] [CONJ-717] correction to support scalar for MySQL --- .../org/mariadb/jdbc/MariaDbConnection.java | 6 +- .../org/mariadb/jdbc/MariaDbStatement.java | 4 +- .../jdbc/internal/com/read/ErrorPacket.java | 2 +- .../failover/AbstractMastersListener.java | 4 + .../jdbc/internal/failover/FailoverProxy.java | 3 + .../jdbc/internal/failover/Listener.java | 2 + .../failover/impl/MastersSlavesListener.java | 6 + .../jdbc/internal/protocol/Protocol.java | 2 +- .../org/mariadb/jdbc/internal/util/Utils.java | 49 +++++--- .../org/mariadb/jdbc/ScalarFunctionsTest.java | 116 ++++++++++++------ src/test/java/org/mariadb/jdbc/UtilTest.java | 2 +- src/test/resources/logback-test.xml | 2 +- 12 files changed, 135 insertions(+), 63 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/MariaDbConnection.java b/src/main/java/org/mariadb/jdbc/MariaDbConnection.java index ce386e062..003a01bf6 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbConnection.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbConnection.java @@ -522,7 +522,7 @@ private PreparedStatement internalPrepareStatement(final String sql, if (sql != null) { - String sqlQuery = Utils.nativeSql(sql, protocol.noBackslashEscapes()); + String sqlQuery = Utils.nativeSql(sql, protocol); if (options.useServerPrepStmts && PREPARABLE_STATEMENT_PATTERN.matcher(sqlQuery).find()) { //prepare isn't delayed -> if prepare fail, fallback to client preparedStatement? @@ -608,7 +608,7 @@ public CallableStatement prepareCall(final String sql, final int resultSetType, + sql); } - String query = Utils.nativeSql(matcher.group(2), protocol.noBackslashEscapes()); + String query = Utils.nativeSql(matcher.group(2), protocol); boolean isFunction = (matcher.group(3) != null); String databaseAndProcedure = matcher.group(8); @@ -712,7 +712,7 @@ private CallableStatement createNewCallableStatement(String query, String proced @Override public String nativeSQL(final String sql) throws SQLException { - return Utils.nativeSql(sql, protocol.noBackslashEscapes()); + return Utils.nativeSql(sql, protocol); } /** diff --git a/src/main/java/org/mariadb/jdbc/MariaDbStatement.java b/src/main/java/org/mariadb/jdbc/MariaDbStatement.java index 48d3aa0fb..1d917a677 100755 --- a/src/main/java/org/mariadb/jdbc/MariaDbStatement.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbStatement.java @@ -330,7 +330,7 @@ private boolean executeInternal(String sql, int fetchSize, int autoGeneratedKeys sql, null); protocol.executeQuery(protocol.isMasterConnection(), results, - getTimeoutSql(Utils.nativeSql(sql, protocol.noBackslashEscapes()))); + getTimeoutSql(Utils.nativeSql(sql, protocol))); results.commandEnd(); return results.getResultSet() != null; @@ -366,7 +366,7 @@ public boolean testExecute(String sql, Charset charset) throws SQLException { results = new Results(this, fetchSize, false, 1, false, resultSetScrollType, resultSetConcurrency, Statement.NO_GENERATED_KEYS, protocol.getAutoIncrementIncrement(), sql, null); protocol.executeQuery(protocol.isMasterConnection(), results, - getTimeoutSql(Utils.nativeSql(sql, protocol.noBackslashEscapes())), charset); + getTimeoutSql(Utils.nativeSql(sql, protocol)), charset); results.commandEnd(); return results.getResultSet() != null; diff --git a/src/main/java/org/mariadb/jdbc/internal/com/read/ErrorPacket.java b/src/main/java/org/mariadb/jdbc/internal/com/read/ErrorPacket.java index b581dd818..c4cd99cc3 100644 --- a/src/main/java/org/mariadb/jdbc/internal/com/read/ErrorPacket.java +++ b/src/main/java/org/mariadb/jdbc/internal/com/read/ErrorPacket.java @@ -95,7 +95,7 @@ public short getErrorNumber() { } public String getSqlState() { - return new String(sqlState); + return sqlState; } public byte getSqlStateMarker() { diff --git a/src/main/java/org/mariadb/jdbc/internal/failover/AbstractMastersListener.java b/src/main/java/org/mariadb/jdbc/internal/failover/AbstractMastersListener.java index 0c6189d8e..fabc6de93 100644 --- a/src/main/java/org/mariadb/jdbc/internal/failover/AbstractMastersListener.java +++ b/src/main/java/org/mariadb/jdbc/internal/failover/AbstractMastersListener.java @@ -432,6 +432,10 @@ public boolean versionGreaterOrEqual(int major, int minor, int patch) { return currentProtocol.versionGreaterOrEqual(major, minor, patch); } + public boolean isServerMariaDb() { + return currentProtocol.isServerMariaDb(); + } + public boolean sessionStateAware() { return currentProtocol.sessionStateAware(); } diff --git a/src/main/java/org/mariadb/jdbc/internal/failover/FailoverProxy.java b/src/main/java/org/mariadb/jdbc/internal/failover/FailoverProxy.java index a65b46416..28b66096a 100644 --- a/src/main/java/org/mariadb/jdbc/internal/failover/FailoverProxy.java +++ b/src/main/java/org/mariadb/jdbc/internal/failover/FailoverProxy.java @@ -95,6 +95,7 @@ public class FailoverProxy implements InvocationHandler { private static final String METHOD_GET_TIMEOUT = "getTimeout"; private static final String METHOD_GET_MAJOR_VERSION = "getMajorServerVersion"; private static final String METHOD_IN_TRANSACTION = "inTransaction"; + private static final String METHOD_IS_MARIADB = "isServerMariaDb"; private static final Logger logger = LoggerFactory.getLogger(FailoverProxy.class); @@ -157,6 +158,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl return this.lock; case METHOD_GET_NO_BACKSLASH: return listener.noBackslashEscapes(); + case METHOD_IS_MARIADB: + return listener.isServerMariaDb(); case METHOD_GET_CATALOG: return listener.getCatalog(); case METHOD_GET_TIMEOUT: diff --git a/src/main/java/org/mariadb/jdbc/internal/failover/Listener.java b/src/main/java/org/mariadb/jdbc/internal/failover/Listener.java index 6f74fa567..5fbd296a7 100644 --- a/src/main/java/org/mariadb/jdbc/internal/failover/Listener.java +++ b/src/main/java/org/mariadb/jdbc/internal/failover/Listener.java @@ -129,6 +129,8 @@ void throwFailoverMessage(HostAddress failHostAddress, boolean wasMaster, boolean versionGreaterOrEqual(int major, int minor, int patch); + boolean isServerMariaDb(); + boolean sessionStateAware(); boolean noBackslashEscapes(); diff --git a/src/main/java/org/mariadb/jdbc/internal/failover/impl/MastersSlavesListener.java b/src/main/java/org/mariadb/jdbc/internal/failover/impl/MastersSlavesListener.java index 3bd60aae9..86cb8ede2 100644 --- a/src/main/java/org/mariadb/jdbc/internal/failover/impl/MastersSlavesListener.java +++ b/src/main/java/org/mariadb/jdbc/internal/failover/impl/MastersSlavesListener.java @@ -235,6 +235,12 @@ public boolean versionGreaterOrEqual(int major, int minor, int patch) { return protocol.versionGreaterOrEqual(major, minor, patch); } + @Override + public boolean isServerMariaDb() { + Protocol protocol = (currentProtocol != null) ? currentProtocol : secondaryProtocol; + return (protocol == null) ? false : protocol.isServerMariaDb(); + } + @Override public boolean sessionStateAware() { Protocol protocol = (currentProtocol != null) ? currentProtocol : secondaryProtocol; diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/Protocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/Protocol.java index cfb9a3679..a5197bc67 100644 --- a/src/main/java/org/mariadb/jdbc/internal/protocol/Protocol.java +++ b/src/main/java/org/mariadb/jdbc/internal/protocol/Protocol.java @@ -268,7 +268,7 @@ void resetStateAfterFailover(long maxRows, int transactionIsolationLevel, String void setActiveFutureTask(FutureTask activeFutureTask); - boolean isServerMariaDb() throws SQLException; + boolean isServerMariaDb(); SQLException handleIoException(Exception initialException); diff --git a/src/main/java/org/mariadb/jdbc/internal/util/Utils.java b/src/main/java/org/mariadb/jdbc/internal/util/Utils.java index 46fe216fe..896dfd8e5 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/Utils.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/Utils.java @@ -267,10 +267,11 @@ public static byte[] copyRange(byte[] orig, int from, int to) { *

      caution: this use MariaDB server conversion: 'SELECT CONVERT('2147483648', INTEGER)' will * return a BIGINT. MySQL will throw a syntax error.

      * - * @param functionString - input string + * @param functionString input string + * @param protocol protocol * @return unescaped string */ - private static String replaceFunctionParameter(String functionString) { + private static String replaceFunctionParameter(String functionString, Protocol protocol) { char[] input = functionString.toCharArray(); StringBuilder sb = new StringBuilder(); @@ -293,7 +294,8 @@ private static String replaceFunctionParameter(String functionString) { // Handle "convert(value, type)" case // extract last parameter, after the last ',' int lastCommaIndex = functionString.lastIndexOf(','); - + int firstParentheses = functionString.indexOf('('); + String value = functionString.substring(firstParentheses + 1, lastCommaIndex); for (index = lastCommaIndex + 1; index < input.length; index++) { if (!Character.isWhitespace(input[index])) { break; @@ -314,12 +316,17 @@ private static String replaceFunctionParameter(String functionString) { } switch (typeParam) { - case "BIGINT": case "BOOLEAN": + return "1=" + value; + + case "BIGINT": case "SMALLINT": case "TINYINT": + typeParam = "SIGNED INTEGER"; + break; + case "BIT": - typeParam = "INTEGER"; + typeParam = "UNSIGNED INTEGER"; break; case "BLOB": @@ -342,9 +349,13 @@ private static String replaceFunctionParameter(String functionString) { typeParam = "CHAR"; break; + case "DOUBLE": case "FLOAT": - typeParam = "DOUBLE"; - break; + if (protocol.isServerMariaDb() || protocol.versionGreaterOrEqual(8,0,17)) { + typeParam = "DOUBLE"; + break; + } + return "0.0+" + value; case "REAL": case "NUMERIC": @@ -384,7 +395,7 @@ private static String replaceFunctionParameter(String functionString) { } } - private static String resolveEscapes(String escaped, boolean noBackslashEscapes) + private static String resolveEscapes(String escaped, Protocol protocol) throws SQLException { if (escaped.charAt(0) != '{' || escaped.charAt(escaped.length() - 1) != '}') { throw new SQLException("unexpected escaped string"); @@ -392,12 +403,12 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) int endIndex = escaped.length() - 1; String escapedLower = escaped.toLowerCase(Locale.ROOT); if (escaped.startsWith("{fn ")) { - String resolvedParams = replaceFunctionParameter(escaped.substring(4, endIndex)); - return nativeSql(resolvedParams, noBackslashEscapes); + String resolvedParams = replaceFunctionParameter(escaped.substring(4, endIndex), protocol); + return nativeSql(resolvedParams, protocol); } else if (escapedLower.startsWith("{oj ")) { // Outer join // the server supports "oj" in any case, even "oJ" - return nativeSql(escaped.substring(4, endIndex), noBackslashEscapes); + return nativeSql(escaped.substring(4, endIndex), protocol); } else if (escaped.startsWith("{d ")) { // date literal return escaped.substring(3, endIndex); @@ -420,19 +431,19 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) // We support uppercase "{CALL" only because Connector/J supports it. It is not in the JDBC // spec. - return nativeSql(escaped.substring(1, endIndex), noBackslashEscapes); + return nativeSql(escaped.substring(1, endIndex), protocol); } else if (escaped.startsWith("{escape ")) { return escaped.substring(1, endIndex); } else if (escaped.startsWith("{?")) { // likely ?=call(...) - return nativeSql(escaped.substring(1, endIndex), noBackslashEscapes); + return nativeSql(escaped.substring(1, endIndex), protocol); } else if (escaped.startsWith("{ ") || escaped.startsWith("{\n")) { // Spaces and newlines before keyword, this is not JDBC compliant, however some it works in // some drivers, // so we support it, too for (int i = 2; i < escaped.length(); i++) { if (!Character.isWhitespace(escaped.charAt(i))) { - return resolveEscapes("{" + escaped.substring(i), noBackslashEscapes); + return resolveEscapes("{" + escaped.substring(i), protocol); } } } else if (escaped.startsWith("{\r\n")) { @@ -441,7 +452,7 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) // so we support it, too for (int i = 3; i < escaped.length(); i++) { if (!Character.isWhitespace(escaped.charAt(i))) { - return resolveEscapes("{" + escaped.substring(i), noBackslashEscapes); + return resolveEscapes("{" + escaped.substring(i), protocol); } } } @@ -452,12 +463,12 @@ private static String resolveEscapes(String escaped, boolean noBackslashEscapes) * Escape sql String. * * @param sql initial sql - * @param noBackslashEscapes must backslash be escape + * @param protocol protocol * @return escaped sql string * @throws SQLException if escape sequence is incorrect. */ @SuppressWarnings("ConstantConditions") - public static String nativeSql(String sql, boolean noBackslashEscapes) throws SQLException { + public static String nativeSql(String sql, Protocol protocol) throws SQLException { if (!sql.contains("{")) { return sql; } @@ -475,7 +486,7 @@ public static String nativeSql(String sql, boolean noBackslashEscapes) throws SQ for (int i = 0; i < charArray.length; i++) { char car = charArray[i]; - if (lastChar == '\\' && !noBackslashEscapes) { + if (lastChar == '\\' && !protocol.noBackslashEscapes()) { sqlBuffer.append(car); continue; } @@ -539,7 +550,7 @@ public static String nativeSql(String sql, boolean noBackslashEscapes) throws SQ inEscapeSeq--; if (inEscapeSeq == 0) { escapeSequenceBuf.append(car); - sqlBuffer.append(resolveEscapes(escapeSequenceBuf.toString(), noBackslashEscapes)); + sqlBuffer.append(resolveEscapes(escapeSequenceBuf.toString(), protocol)); escapeSequenceBuf.setLength(0); continue; } diff --git a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java index ab14d0291..e189695af 100644 --- a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java +++ b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.math.BigInteger; import java.sql.PreparedStatement; @@ -42,37 +43,75 @@ public class ScalarFunctionsTest extends BaseTest { @Test public void nativeSqlTest() throws SQLException { + String exp; + if (isMariadbServer() || minVersion(8, 0, 17)) { + exp = + "SELECT convert(foo(a,b,c), SIGNED INTEGER)" + + ", convert(convert(?, CHAR), SIGNED INTEGER)" + + ", 1=?" + + ", 1=?" + + ", convert(?, SIGNED INTEGER )" + + ", convert (?, SIGNED INTEGER )" + + ", convert(?, UNSIGNED INTEGER)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, DOUBLE)" + + ", convert(?, DOUBLE)" + + ", convert(?, DECIMAL)" + + ", convert(?, DECIMAL)" + + ", convert(?, DECIMAL)" + + ", convert(?, DATETIME)" + + ", convert(?, DATETIME)"; + } else { + exp = + "SELECT convert(foo(a,b,c), SIGNED INTEGER)" + + ", convert(convert(?, CHAR), SIGNED INTEGER)" + + ", 1=?" + + ", 1=?" + + ", convert(?, SIGNED INTEGER )" + + ", convert (?, SIGNED INTEGER )" + + ", convert(?, UNSIGNED INTEGER)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, BINARY)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", convert(?, CHAR)" + + ", 0.0+?" + + ", 0.0+?" + + ", convert(?, DECIMAL)" + + ", convert(?, DECIMAL)" + + ", convert(?, DECIMAL)" + + ", convert(?, DATETIME)" + + ", convert(?, DATETIME)"; + } + assertEquals( - "SELECT convert(foo(a,b,c), INTEGER)" - + ", convert(convert(?, CHAR), INTEGER)" - + ", convert(?, INTEGER )" - + ", convert(?, INTEGER)" - + ", convert(?, INTEGER )" - + ", convert (?, INTEGER )" - + ", convert(?, INTEGER)" - + ", convert(?, BINARY)" - + ", convert(?, BINARY)" - + ", convert(?, BINARY)" - + ", convert(?, BINARY)" - + ", convert(?, BINARY)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, CHAR)" - + ", convert(?, DOUBLE)" - + ", convert(?, DOUBLE)" - + ", convert(?, DECIMAL)" - + ", convert(?, DECIMAL)" - + ", convert(?, DECIMAL)" - + ", convert(?, DATETIME)" - + ", convert(?, DATETIME)", + exp, sharedConnection.nativeSQL( "SELECT {fn convert(foo(a,b,c), SQL_BIGINT)}" + ", {fn convert({fn convert(?, SQL_VARCHAR)}, SQL_BIGINT)}" @@ -110,11 +149,12 @@ public void nativeSqlTest() throws SQLException { public void scalarFctTest() throws SQLException { queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", 2147483648L, 2147483648L); queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", BigInteger.valueOf(2147483648L), 2147483648L); - queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", 20, 20); - queryScalar("SELECT {fn convert(?, SQL_BOOLEAN)}", true, 1); - queryScalar("SELECT {fn convert(?, SQL_SMALLINT)}", 5000, 5000); - queryScalar("SELECT {fn convert(?, SQL_TINYINT)}", 5000, 5000); - queryScalar("SELECT {fn convert(?, SQL_BIT)}", 255, 255); + queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", 20, new Object[] {20, 20L}); + queryScalar("SELECT {fn convert(?, SQL_BOOLEAN)}", true, new Object[] {1, 1L}); + queryScalar("SELECT {fn convert(?, SQL_SMALLINT)}", 5000, new Object[] {5000, 5000L}); + queryScalar("SELECT {fn convert(?, SQL_TINYINT)}", 5000, new Object[] {5000, 5000L}); + queryScalar( + "SELECT {fn convert(?, SQL_BIT)}", 255, new Object[] {255L, BigInteger.valueOf(255L)}); queryScalar("SELECT {fn convert(?, SQL_BINARY)}", "test", "test".getBytes()); queryScalar( "SELECT {fn convert(?, SQL_DATETIME)}", @@ -131,6 +171,12 @@ private void queryScalar(String sql, Object val, Object res) throws SQLException if (obj instanceof byte[]) { byte[] arr = (byte[]) obj; assertArrayEquals((byte[]) res, arr); + } else if (res instanceof Object[]) { + Object[] resArr = (Object[]) res; + for (int i = 0; i < resArr.length; i++) { + if (resArr[i].equals(obj)) return; + } + fail("not expected result"); } else { assertEquals(res, rs.getObject(1)); } diff --git a/src/test/java/org/mariadb/jdbc/UtilTest.java b/src/test/java/org/mariadb/jdbc/UtilTest.java index 8fba59739..a8fd84740 100644 --- a/src/test/java/org/mariadb/jdbc/UtilTest.java +++ b/src/test/java/org/mariadb/jdbc/UtilTest.java @@ -98,7 +98,7 @@ public void escape() throws SQLException { "-- Also note that you can safely include { and } in comments" }; for (int i = 0; i < inputs.length; i++) { - assertEquals(Utils.nativeSql(inputs[i], false), outputs[i]); + assertEquals(sharedConnection.nativeSQL(inputs[i]), outputs[i]); } } diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index adf279e2c..a58102026 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -60,7 +60,7 @@ - + From 3ce25357a3569845fc0bfcef830c2edc0cef03eb Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 2 Aug 2019 11:00:16 +0200 Subject: [PATCH 15/19] [CONJ-719] LocalTime fractional test correction for MySQL 5.5 that doesn't support fractional dates --- src/test/java/org/mariadb/jdbc/LocalTimeTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java index b9850c37d..1be441777 100644 --- a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java @@ -19,6 +19,9 @@ public class LocalTimeTest extends BaseTest { @Test public void localTimeTest() throws SQLException { + if (!isMariadbServer()) { + cancelForVersion(5, 5); + } Statement stmt = sharedConnection.createStatement(); stmt.execute("CREATE TEMPORARY TABLE LocalTimeTest(val TIME(6), val2 TIME)"); try (PreparedStatement prep = @@ -77,6 +80,9 @@ public void localTimeTest() throws SQLException { @Test public void localDateTest() throws SQLException { + if (!isMariadbServer()) { + cancelForVersion(5, 5); + } Statement stmt = sharedConnection.createStatement(); stmt.execute("CREATE TEMPORARY TABLE LocalDateTest(val DATE)"); try (PreparedStatement prep = From 21918fd3fd364fa26137c922798dc0c35ee2128c Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 2 Aug 2019 11:12:42 +0200 Subject: [PATCH 16/19] bump 2.4.3 version --- README.md | 4 ++-- documentation/changelog.creole | 7 +++++++ pom.xml | 4 ++-- .../org/mariadb/jdbc/internal/util/constant/Version.java | 4 ++-- src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java | 4 +++- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b9f9a1aa4..f8bb06259 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Tracker link https://ji |:------------:|:-------------------------:| | 6 | 1.7.4 | | 7 | 1.7.4 | -| 8+ | 2.4.2 | +| 8+ | 2.4.3 | The driver (jar) can be downloaded from [mariadb connector download](https://mariadb.com/products/connectors-plugins) or maven : @@ -32,7 +32,7 @@ or maven : org.mariadb.jdbc mariadb-java-client - 2.4.0 + 2.4.3 ``` diff --git a/documentation/changelog.creole b/documentation/changelog.creole index 56606e24a..faf954460 100644 --- a/documentation/changelog.creole +++ b/documentation/changelog.creole @@ -1,4 +1,11 @@ +== 2.4.3 - Released on 02 Jul. 2019 + +* [CONJ-717] conversion function support for other data type than default MariaDB conversion type +* [CONJ-722] Permit suppression of result-set metadata getTableName for oracle compatibility +* [CONJ-719] Saving values using Java 8 LocalTime does not store fractional parts of seconds +* [CONJ-716] Correcting possible NPE on non thread safe NumberFormat (logging) + == 2.4.2 - Released on 17 Jun. 2019 Security diff --git a/pom.xml b/pom.xml index 74561d4ec..06201a0cf 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ mariadb-java-client jar mariadb-java-client - 2.4.2 + 2.4.3 JDBC driver for MariaDB and MySQL https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/ @@ -71,7 +71,7 @@ 2.17 2 4 - 2 + 3 diff --git a/src/main/java/org/mariadb/jdbc/internal/util/constant/Version.java b/src/main/java/org/mariadb/jdbc/internal/util/constant/Version.java index e931a5170..d925ea20f 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/constant/Version.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/constant/Version.java @@ -53,9 +53,9 @@ package org.mariadb.jdbc.internal.util.constant; public final class Version { - public static final String version = "2.4.2"; + public static final String version = "2.4.3"; public static final int majorVersion = 2; public static final int minorVersion = 4; - public static final int patchVersion = 2; + public static final int patchVersion = 3; public static final String qualifier = ""; } \ No newline at end of file diff --git a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java index e189695af..0790f78b6 100644 --- a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java +++ b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java @@ -174,7 +174,9 @@ private void queryScalar(String sql, Object val, Object res) throws SQLException } else if (res instanceof Object[]) { Object[] resArr = (Object[]) res; for (int i = 0; i < resArr.length; i++) { - if (resArr[i].equals(obj)) return; + if (resArr[i].equals(obj)) { + return; + } } fail("not expected result"); } else { From 896bcde4f40ca2aa906e62dd72cf9f7f46bf17b0 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 2 Aug 2019 11:30:55 +0200 Subject: [PATCH 17/19] [misc] correcting test for aurora, since error message change according to aurora version --- src/test/java/org/mariadb/jdbc/ErrorMessageTest.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java b/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java index 5c6356179..ccbc4e201 100644 --- a/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java +++ b/src/test/java/org/mariadb/jdbc/ErrorMessageTest.java @@ -359,11 +359,7 @@ public void testSmallMultiBatchErrorMessageNoBulk() { executeBatchWithException(connection); fail("Must Have thrown error"); } catch (SQLException sqle) { - if (sharedIsAurora()) { - assertTrue(sqle.getCause().getCause().getMessage().contains( - "INSERT INTO testErrorMessage(test, test2) values (?, ?), " - + "parameters ['more than 10 characters to provoc error',10]")); - } else { + if (!sharedIsAurora()) { assertTrue("message : " + sqle.getCause().getCause().getMessage(), sqle.getCause().getCause().getMessage().contains( "INSERT INTO testErrorMessage(test, test2) values " From 13c8721a306fe8f1a6a67c9282ce04c00c269892 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 2 Aug 2019 12:26:00 +0200 Subject: [PATCH 18/19] [misc] LocalDateTime test with microseconds test removal for MySQL 5.5 --- src/test/java/org/mariadb/jdbc/LocalTimeTest.java | 3 +++ src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java index 1be441777..0c95ea5c0 100644 --- a/src/test/java/org/mariadb/jdbc/LocalTimeTest.java +++ b/src/test/java/org/mariadb/jdbc/LocalTimeTest.java @@ -112,6 +112,9 @@ public void localDateTest() throws SQLException { @Test public void localDateTimeTest() throws SQLException { + if (!isMariadbServer()) { + cancelForVersion(5, 5); + } Statement stmt = sharedConnection.createStatement(); stmt.execute("CREATE TEMPORARY TABLE LocalDateTimeTest(val DATETIME(6), val2 DATETIME)"); try (PreparedStatement prep = diff --git a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java index 0790f78b6..1f7657c6e 100644 --- a/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java +++ b/src/test/java/org/mariadb/jdbc/ScalarFunctionsTest.java @@ -147,6 +147,9 @@ public void nativeSqlTest() throws SQLException { @Test public void scalarFctTest() throws SQLException { + if (!isMariadbServer()) { + cancelForVersion(5, 5); + } queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", 2147483648L, 2147483648L); queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", BigInteger.valueOf(2147483648L), 2147483648L); queryScalar("SELECT {fn convert(?, SQL_BIGINT)}", 20, new Object[] {20, 20L}); From 712d9d6e18f2a464e2d39f0fa9c122d280eb0321 Mon Sep 17 00:00:00 2001 From: rusher Date: Fri, 2 Aug 2019 15:17:14 +0200 Subject: [PATCH 19/19] [misc] Ed25519 test removal for Maxscale environment --- src/test/java/org/mariadb/jdbc/ConnectionTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/org/mariadb/jdbc/ConnectionTest.java b/src/test/java/org/mariadb/jdbc/ConnectionTest.java index 9c0bc6df0..f8a0a9953 100644 --- a/src/test/java/org/mariadb/jdbc/ConnectionTest.java +++ b/src/test/java/org/mariadb/jdbc/ConnectionTest.java @@ -580,6 +580,7 @@ public void run() { @Test public void verificationEd25519AuthPlugin() throws Throwable { + Assume.assumeTrue(System.getenv("MAXSCALE_VERSION") == null); Assume.assumeTrue(isMariadbServer() && minVersion(10, 2)); Statement stmt = sharedConnection.createStatement();