Can I run a "source" command (SQL script) from a JDBC connection? - java

I'm writing an application that has a data access layer to abstract the underlying connections to SQLITE3 or MySQL databases.
Thanks to some help here yesterday I was shown how to use a process builder to run a command line import into the SQLITE3 DB using output redirection.
Now I am trying to create the same database but in MySQL by importing a dump file. The load works fine from the command line client. I just tell it to source the file and the DB is created successfully.
However I am trying to do this through code at runtime and my method for executing a SQL statement fails to execute the source command.
I suspect that this is because "source" is not SQL but I don't know what else to use to try and run it.
My error message is:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'source /tmp/ISMCoreActionPack_mysql.sql' at line 1
The failing command string:
source /tmp/ISMCoreActionPack_mysql.sql;
My method is:
public Boolean executeSqlStatement(String sql) {
Boolean rc = false;
try {
Connection connection = getConnection();
Statement statement = connection.createStatement();
rc = statement.execute(sql);
connection.close();
} catch (SQLException e) {
e.printStackTrace();
System.err.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(1);
}
return rc;
}
Can anyone suggest how to do this?

You cannot run 'source' command, because it's not supported by JDBC driver, only MySQL.
My advice to you the following. Write some parser, which reads queries from a file, and executes them using JDBC statements.

source is not part of MySQL's dialect of SQL; it is a MySQL shell command. Still, you shouldn't need to write your own parser. You could use something like SqlTool as explained in this answer.

Related

HSQLDB Backup Query gives COMPRESSED error

To backup HSQLDB catalog in manaual :
BACKUP DATABASE TO directory name BLOCKING [ AS FILES ]
when I apply in calableStatement :
try {
cs = conn.prepareCall("BACKUP DATABASE COMPRESSED TO './backup/' BLOCKING ");
cs.execute();
cs.close();
} catch (SQLException e) {
e.printStackTrace();
}
1- If I add COMPRESSED and execute I get SQL exception :
java.sql.SQLSyntaxErrorException: unexpected token: COMPRESSED required: TO in statement [BACKUP DATABASE COMPRESSED TO './backup/' BLOCKING ]
2- If I remove COMPRESSED ...the sql query complains that COMPRESSED should be added (attached)...Though zip backup folder gets created ..
NOTE: using jave 8 , HSQLDB 2.4 Server Remote ,IntelliJ IDEA ,database name is ProDB.
The syntax for this command allows the settings only at the end of the statement:
BACKUP DATABASE TO <file path> [SCRIPT] {[NOT] COMPRESSED} {[NOT] BLOCKING} [AS FILES]
It looks like the suggestion is generated only by IntelliJ.
Please note use of prepareCall is required only for calling procedures and functions. It is better to use prepareStatement for all other executions.

Can you use JDBC to connect to just an instance without specifying a database?

I am working on an JAVA app that evaluates the data and log sizes of all databases on an instance and mails a monthly report. I am currently working with SQLServer2014. I am using an SQL query that calculates the size of all databases by querying sys.master_files.
The problem is that when using JDBC to make the query, it returns the error:
java.sql.SQLException: No suitable driver found for jdbc:microsoft:sqlserver://localhost"
I have tried connecting to particular databases and that works fine. Is there any way to do this query directly to sys.master_files using JDBC? Or is there a smarter way altogether to accomplish the same result?
Thanks
Your "No suitable driver found" error is simply due to a malformed connection URL. jdbc:microsoft:sqlserver is not valid.
As for connecting to an instance without specifying a particular database, this works fine for me:
// NB: no databaseName specified in the following
String connectionUrl = "jdbc:sqlserver://localhost;instanceName=SQLEXPRESS;integratedSecurity=true";
try (Connection conn = DriverManager.getConnection(connectionUrl)) {
String sql = "SELECT name FROM sys.master_files WHERE type_desc='ROWS' ORDER BY database_id";
try (
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql)) {
while (rs.next()) {
System.out.println(rs.getString(1));
}
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
Note that sys.master_files is a system view that is available in all databases, so AFAIK it doesn't matter what the current database (catalog) is when you call it.

Teradata external Java Stored Procedure error: No suitable driver found for jdbc:default:connection

I wrote a Java stored procedure, packed it into a jar and installed it into the Teradata database. I want to use the default database connection as described here. Most of the code was generated by the Teradata wizard for stored procedures.
public class TestSql {
public static void getEntryById(int id, String[] resultStrings) throws SQLException {
Connection con = DriverManager.getConnection("jdbc:default:connection");
String sql = "SELECT x FROM TEST_TABLE WHERE ID = " + id + ";";
Statement stmt = (Statement) con.createStatement();
ResultSet rs1 = ((java.sql.Statement) stmt).executeQuery(sql);
rs1.next();
String resultString = rs1.getString(1);
stmt.close();
con.close();
resultStrings[0] = resultString;
}
}
I installed the jar:
CALL SQLJ.REPLACE_JAR('CJ!/my/path/Teradata-SqlTest.jar','test');
And created the procedure:
REPLACE PROCEDURE "db"."getEntryById" (
IN "id" INTEGER,
OUT "resultString" VARCHAR(1024))
LANGUAGE JAVA
MODIFIES SQL DATA
PARAMETER STYLE JAVA
EXTERNAL NAME 'test:my.package.TestSql.getEntryById(int,java.lang.String[])';
Now when I call this procedure, I get this error message:
Executed as Single statement. Failed [7827 : 39001] Java SQL Exception SQLSTATE 39001: Invalid SQL state (08001: No suitable driver found for jdbc:default:connection).
Now when I log off from Teradata and log on again and call the procedure, the error message becomes:
Executed as Single statement. Failed [7827 : 39001] A default connection for a Java Stored Procedure has not been established for this thread.).
What is the problem here? I'm connecting to Teradata using the Eclipse plugin. Teradata v. 15.0.1.01.
After many hours I finally found the problem. Eclipse packed all dependencies into the jar - which basically is ok. However it also packed the Teradata JDBC driver files (tdgssconfig.jar and terajdbc4.jar) into the result jar, which was the problem.
I adjusted the jar building process so that these files are not included and the errors went away.

Reading Single Excel file concurrently in java

We got this requirement while trying to run our framework from two different Jenkins jobs
Following is our code:
String xlsPath= System.getProperty("user.dir")+"\\TestInputs\\Config.xls";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection("jdbc:odbc:Driver={Microsoft Excel Driver (*.xls)};DBQ=" +xlsPath+ ";DriverID=22;READONLY=TRUE","","");
String sql="Select * from [Setup$]";
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
while(rs.next())
{
System.out.println(rs.getString(1).toString());
System.out.println(rs.getString(2).toString());
System.out.println(rs.getString(3).toString());
Thread.sleep(1000);
}
rs.close();
st.close();
conn.close();
The above code working absolutely fine when we are trying to execute through multi threading concept.
But I am getting following error message if I create TWO JENKINS JOBS and running them parallely.
Exception in thread "main" java.sql.SQLException: [Microsoft][ODBC Excel Driver] The Microsoft Jet database engine cannot open the file '(unknown)'. It is already opened exclusively by another user, or you need permission to view its data.
Do we have any workaround for this? so that I can execute two jobs without any issues.
NOTE: I cannot use HSSF or someother means to read my excel file. I should strictly use Database commands like I used it in the above code.
Please help !

Calling Oracle "DEFINE" from Java

I need to define some variables in Oracle to be used further down our application's database installation scripts. Basically, the way our installer works now is it reads in the script files and calls each one via JDBC in Java. I need to have Oracle do the variable substitution on the database side, as there are procedures, triggers, create statements, etc. that will need to refer to them (So like "CREATE TABLE &&MYSCHEMA.TBL_NAME ...").
The problem I am having is that the DEFINE statement is throwing an error when calling it from Java (example):
private static void testDefineVariables() {
String url = "jdbc:oracle:thin:#localhost:1521:LOCALDEV";
String username = "SYSTEM";
String password = "manager42";
Connection conn = null;
Statement stmt = null;
try {
conn = DriverManager.getConnection(url, username, password);
stmt = conn.createStatement();
//Execute the sql
stmt.execute("DEFINE MYSCHEMA='TESTSCHEMA'");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
The error is:
java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:439)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:395)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:802)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:436)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:521)
at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:194)
at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:1000)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1307)
at oracle.jdbc.driver.OracleStatement.executeInternal(OracleStatement.java:1882)
at oracle.jdbc.driver.OracleStatement.execute(OracleStatement.java:1847)
at oracle.jdbc.driver.OracleStatementWrapper.execute(OracleStatementWrapper.java:301)
I am using an Oracle 11g R2 database with the ojdbc6-11.2.0.1.0.jar JDBC driver. I am able to execute the statement successfully from the sqldeveloper tool as well as the SQLPlus console, but not from the Java application. Do I need to configure additional properties on the database driver? Can I make this type of call from this driver?
I know some people right off the bat may suggest using variable bindings on the Java side, but this is not an option. The scripts need to be executable from both the SQL interface and the installer. There are other reasons apart from this one, which I won't go into.
I am also hoping to get this to work with the sql-maven-plugin, but that may not be possible based on this JIRA:
Add Oracle SQLPlus syntax for substitution variables
If anyone has any suggestions or know how to get this to work, I would greatly appreciate it.
I don't think DEFINE will work outside of SQLPLUS - JAVA uses JDBC
and assumes the argument to execute() is valid SQL. If you're able to
use DEFINE outside SQLPLUS it means the utility you're using is
intended to be compatible with or a partial replacement of SQLPLUS.
DEFINE is an SQLPLUS command - SQLPLUS is an ORACLE utility.
According to this URL Define is not an SQL statement
http://www.adp-gmbh.ch/ora/sqlplus/define.html
Both DEFINE and the substitution variable syntax &&MYSCHEMA.TBL_NAME are SQL*Plus commands. They are not valid SQL or PL/SQL constructs. You won't be able to use them as-is via JDBC.
Depending on the reasons that you say you don't want to go into
Your Java application can call out to the operating system to invoke SQL*Plus and pass in the script
Your Java application can implement whatever SQL*Plus features your scripts rely on. Rather than executing DEFINE MYSCHEMA='TESTSCHEMA', your application would need to maintain, say, a HashMap that maps a variable like myschema to a value like TESTSCHEMA. Your application would then have to parse the individual SQL statements looking for text like &&MYSCHEMA, replace that with the value from its local HashMap, and then send the resulting SQL string to the database server. Depending on how much of the SQL*Plus functionality you need to replicate, that could be a reasonably significant undertaking. Many PL/SQL IDEs (such as Toad or SQL Developer) implement a subset of SQL*Plus's functionality-- I don't know of any that have tried to implement every last SQL*Plus feature.

Categories