How to create and drop database, schema PostgreSQL by Java code? - java

I try
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import com.ibatis.common.jdbc.ScriptRunner;
public static void createDatabase() throws ClassNotFoundException, SQLException {
Class.forName("org.postgresql.Driver");
Connection connection = DriverManager.getConnection("jdbc:postgresql://127.0.0.1:5432/postgres", "postgres", "123456a#");
Statement stmt = connection.createStatement();
stmt.executeQuery("CREATE DATABASE IF NOT EXISTS foo");
stmt.executeQuery("USE foo");
connection.close();
}
and
public static void dropDatabase() throws ClassNotFoundException, SQLException {
Class.forName("org.postgresql.Driver");
Connection connection = DriverManager.getConnection("jdbc:postgresql://127.0.0.1:5432/", "postgres", "123456a#");
Statement statement = connection.createStatement();
statement.executeUpdate("DROP DATABASE foo");
connection.close();
}
but create, also drop method not success.
Error when call create method:
Exception in thread "main" org.postgresql.util.PSQLException: ERROR: syntax error at or near "NOT"
Position: 20
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2453)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2153)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:286)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:432)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:358)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:305)
at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:291)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:269)
at org.postgresql.jdbc.PgStatement.executeQuery(PgStatement.java:236)
at com.nttdata.RunSqlScript.createDatabase(RunSqlScript.java:57)
at com.nttdata.RunSqlScript.main(RunSqlScript.java:27)
Error when call drop method:
Exception in thread "main" org.postgresql.util.PSQLException: ERROR: database "foo" is being accessed by other users
Detail: There is 1 other session using the database.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2453)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2153)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:286)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:432)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:358)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:305)
at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:291)
at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:269)
at org.postgresql.jdbc.PgStatement.executeUpdate(PgStatement.java:249)
at com.nttdata.RunSqlScript.dropDatabase(RunSqlScript.java:71)
at com.nttdata.RunSqlScript.main(RunSqlScript.java:28)

Firstly, the SQL syntax used while creating a database is incorrect in your question. The stack trace says it all about the incorrect syntax.
If you want to check whether the database exists or not, then you might have to do something like this in your Java code:
ResultSet rs = stmt.executeQuery("select datname from pg_database where datname like 'foo';");
not by the IF NOT EXISTS approach
Accessing this rs object will let you know whether the database exists or not. Then you can fire either your CREATE or DELETE database operations accordingly.
String databaseName = "";
if(rs.next()) {
databaseName = rs.getString("datname");
}
stmt.executeQuery("DROP DATABASE " + databaseName);
If a direct DROP DATABASE doesn't work (which I had faced a lot many times), you might consider using the dropdb utility or by one of the following approaches.
APPROACH-1
Use the following query to prevent future connections to your database(s):
REVOKE CONNECT ON DATABASE foo FROM public;
You can then terminate all connections to this database except your own:
SELECT pid, pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = current_database() AND pid <> pg_backend_pid();
Since that you have revoked the CONNECT rights to the corresponding database, no external auto-connect's will no longer be able to do so. You'll now be able to drop the database without any issues.
APPROACH-2:
This approach goes by the batch job way, where you can invoke this class from the corresponding jar:
Process batchProcess = Runtime.getRuntime().exec("C:/Program Files/PostgreSQL/9.5/bin/psql -h \"DB SERVER ADDRESS\" -U postgres -f C:/batch.sql");
batch.sql holds the SQL DROP DATABASE statements, which will be dropped when executed.
Hope this helps!

An option that you can try to use is to use a database migration tool like liquibase. There are couple of options that you can try from liquibase. One is to have an executable directly executed from the code (You first create a database change log file , with change sets. One of the commands in the change sets will be an executable
<changeSet author="exec-change-drop" id="drop-foo">
<executeCommand executable="<bat file with drop for PSQL or dropdb>"/>
</changeSet>
Another option that you can try is to write a sql and call it
<changeSet id="exec-change-drop2" author="drop-foo-2">
<sql>DROP DATABASE foo;</sql>
</changeSet>
You can then execute this from your code as follows
Class.forName("org.postgresql.Driver");
Connection connection = DriverManager.getConnection("jdbc:postgresql://127.0.0.1:5432/postgres", "postgres", "123456a#");
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
Liquibase liquibase = new liquibase.Liquibase("path/to/changelog.xml", new ClassLoaderResourceAccessor(), database);
liquibase.update(new Contexts(), new LabelExpression());
Note that your changeLogSchema may need to be in a different schema so that it executes seamlessly.
Additionally liquibase can be added with maven (this was the way it was supposed to be) and executed as well

Related

H2 embedded database intellij idea <-> sources files

something wrong here but don't understand where, im trying to use H2 database as a local, "Embedded" database for my java project. So after generating my db, i created table and sample data with intellij database console but when i try to connect with sources files i fail my requests
Here is my intellij entry :
https://i.stack.imgur.com/F5Qo9.png
And here my source files entry :
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Database {
private Connection conn;
private Statement st;
public Database() {
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
this.conn = DriverManager.getConnection("jdbc:h2:" + "./ava", "root", "password");
System.out.println("Status : connected");
st = conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
}
I just don't how understand how i cannot have access to my datas, i have
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "POSTE" non trouvée
Table "POSTE" not found; SQL statement:
SELECT * FROM POSTE [42102-200]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:453)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
at org.h2.message.DbException.get(DbException.java:205)
at org.h2.message.DbException.get(DbException.java:181)
at org.h2.command.Parser.readTableOrView(Parser.java:7628)
(...)
when i'm trying to req "SELECT * FROM POSTE"
./ava is a relative database path. . means the current working directory of a process. Your IDE and your application launched from that IDE usually have different working directories.
You need to use absolute database paths (C:\path\to\db or /path/to/db) or you can use paths relative to the home directory of your user (~/…).
You also need to make sure that DB tool in your IDE and your application both use exactly the same version of H2, because you use embedded databases. When you use different versions of H2 with the same embedded database file, this file may be corrupted. (When you use H2 server process, you may safely connect to it using different versions of H2's drivers.)

Error or wrong type of code while creating connection & execute SQL query statements using mysql in java

I'm using MySQL 5.7 with Java in Eclipse, and the connection statement below code below is causing an error when I try to connect:
try
{
//1. Get a connection to database
jdbc:mysql://localhost:3306/databaseName?autoReconnect=true;useSSL=false;
// 2. Create a statement
Statement myStmt=myConn.createStatement();
// 3. Execute SQL query
ResultSet myRs=myStmt.executeQuery("select * from employee");
//4. Process the result set
while(myRs.next())
{
System.out.println(myRs.getString("last_name")+","+myRs.getString("first_name"));
}
}
catch(Exception exc){
exc.printStackTrace();
}
First things first.
Code will only be used to validate the error. So you must paste the error fired by your program.
Since we don't have enough information to the problem, I will just cover basic troubleshooting.
Basic trouble shooting:
Do you have the driver? if not, you can download it here.
Next, Do you have the driver on your project class path? If not yet, you must add it. see how here
Did you load the driver to the program? if not, Class.forName("com.mysql.jdbc.Driver"); // Load Driver like that before doing anything.
Did you establish the connection? if not, Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/DATABASE","USERNAME","PASSWORD");//3306 or port number depends on you config, same with DATABASE, USERNAME, PASSWORD
After the connection were established, so you should create a statement object like Statement s = con.createStatement(); // Create Statement. This will be used to execute sql commands.
finally, you can execute the commands like s.execute("select * from employee"); // Execute Query NOTE that s here is the variable created on number 5.
If all of the above were properly done but still gets an error, check if your have the database server running. In you case, mysql. Make sure there were not other installation of mysql prior to your current mysql. Sometimes, it will mess up your database. Troubleshooting your mysql, see mysql official doc here
While possible error is the datatype of mysql to your java code or getting a column that does not exist on your query or worse the column does not exist on your table.
Hope that help you and other who needs it.

How can I check that Java JDBC code uses the right column names?

I have a test suite of end-to-end tests. They are supposed to catch typos in SQL statements, bad table or column names (anything where DB schema and Java code disagree), or missing DB permissions. I don't want to rely on data in the database (too complicated to set up); this is just a basic test.
import java.sql.*;
import org.junit.Test;
public class TypoTest {
private Connection getConnection() throws Exception {
String connectionString = "jdbc:postgresql://127.0.0.1:5432/db";
String driverClassName = "org.postgresql.ds.PGConnectionPoolDataSource";
Class.forName(driverClassName).newInstance();
return DriverManager.getConnection(connectionString, "robert", "");
}
#Test
public void runQuery() throws Exception {
try (Connection connection = getConnection();
PreparedStatement ps = connection.prepareStatement("SELECT relname FROM pg_catalog.pg_class");
ResultSet data = ps.executeQuery()) {
while (data.next()) {
data.getString("relname");
}
}
}
}
When I run the above test, it fails if I have a typo in the SELECT statement. (Good.) If I have a typo in the column name in data.getString("typo here"), that won't get caught if the table queried does not have data because then the loop is never entered. To keep the test (setup) simple, I don't want to insert data into my tables first.
I guess I could make the column names into constants and DRY up my code and get rid of the problem.
However, I am wondering if there is an easier way... I am lazy and don't want to edit all my queries. Is there a better way to unit-test my SQL?
I am using Postgres 9.5 and JDBC 4.
I guess you already have the answer you seek but just for the sake of answering, you can try using result-set-metadata by using a select * from table and then checking the column names against your query (you'd have to parse the query string I guess...).
I believe it will work for empty tables as well but do note that I have not tested the empty table scenario.

Moving from MySQL to MS Azure SQL Database

I have a J2EE web application that issues parameterized SQL queries to a MySQL back-end. I need to replace the back-end with MS Azure SQL Database. I have migrated the DB and data over to MS Azure SQL Database. However all my queries from the app are failing. For example the following query (shown with the wrapping code) runs perfectly fine in the Management Studio but fails in the java code:
PreparedStatement statement = dbConnection.prepareStatement("SELECT * FROM [mydb].[apps] WHERE [key] = ?;");
statement.setString(1, appKey);
ResultSet resultSet = statement.executeQuery();
The error I get is:
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near the keyword 'key'.
I tried various things like removing the [], qualifying the column name with the table name, etc. but nothing works.
Also one more question: The JDBC connection I am using string includes the database name (mydb) so I don't want to include it in each of my SQL statement. I never did for MySQL so I'd rather avoid doing it now since it would require me to manually add the DB name to each statement in the code. However if I remove the DB name from the above query it again fails with error Invalid object name 'apps'. Why isn't the DB specified in the connection string being used as the default one? The connection string I am using is jdbc:sqlserver://{servername}.database.windows.net:1433;database=mydb;user={username}#{servername};password={password};encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
BTW I am using the Azure SQL Database V12 and connecting via Microsoft JDBC Driver 4.2 for SQL Server.
I tried to reproduce your issue, but my sample code ran fine. Per my experience, I think that the issue cause is by using incorrect table name form.
The MSSQL table name completed form is <db_name>.<owner_name>.<table_name>. Its short form could be <owner_name>.<table_name> or <table_name>. The item can be <item> or [<item>].
Sample Code (for Azure SQL Database, the same principle as MSSQL on Azure VM):
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String jdbcUrl = "jdbc:sqlserver://<host_name>:1433;database=<db_name>;";
//The completed connection string is jdbc:sqlserver://<host_name>:1433;database=<db_name>;user=<user like username#server_name>;password={your_password_here};encrypt=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
String user = "<user>";
String password = "<password>";
Connection conn = DriverManager.getConnection(jdbcUrl, user, password);
String sql = "SELECT * FROM person WHERE name = ?;" // My test table is 'person'
// The table name could be person, [person], dbo.person, [dbo].[person], <db_name>.dbo.person, [<db_name>].[dbo].[person]
PreparedStatement statement = conn.prepareStatement(sql);
statement.setString(1, "Peter Pan");
ResultSet rs = statement.executeQuery();
while(rs.next()) {
System.out.println(rs.getLong("id")+","+rs.getString("name"));
}
}
}
I suggest you to use the third-party Universal Database Management Tool "Dbeaver". It based on Eclipse and used JDBC Driver to connect kinds of Database include MSSQL. You can create db connection to MSSQL on Azure VM and test SQL queries.
Best Regards.

Java DB Schema 'TEST' does not exist

Hy!!!
I want to make a small DB Demo.
My Error is: Schema 'TEST' does not exist
Picture:
Run a "CREATE SCHEMA TEST" one time to create the schema.
perhaps it is to late but it can be useful for other people who read this site to know the solution to this problem.
You have to enable the APP Schema : right klick on APP and then click => Set as default Schema
Envoy
I was able to establish a connection with an uninitialized database, using that user, with the following code:
package derby;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class DerbyTest {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
Connection connection= DriverManager.getConnection("jdbc:derby:testdb;create=true", "test", "test");
Statement s=connection.createStatement();
s.execute("create table test_table (name varchar(128))");
connection.close();
}
}
The main difference between your code and mine is that I used the embedded driver, not the network client, and I created a table in the test, of course. I was not able to replicate the problem you describe.
Its very simple
You Have to write
APP.TEST
don't write simple TEST (as test schema does not exist).
For example you created a table test in database as you show snapshot
then
INSERT INTO TEST (.....) STATEMENT
will not work.
Instead
INSERT INTO APP.TEST (....)
will work.

Categories

Resources