In H2 there are two ways to create a new in-memory database. In the first, you explicitly create the database with a CREATE DATABASE.. SQL statement. In the other, if you attempt to connect to a non-existent database, H2 will simply create it. I've elected the first way because if I don't get some kind of error back how will I know to create the single table (with only two columns).
The problem is that H2 doesn't like he SQL I'm using and flags an error. This SQL statement:
String sql = "CREATE DATABASE Tickets, " + USER + ", " + PASS;
throws this exception:
org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "CREATE DATABASE[*] TICKETS, USERNAME, PASSWORD "; expected "OR, FORCE, VIEW, ALIAS, SEQUENCE, USER, TRIGGER, ROLE, SCHEMA, CONSTANT, DOMAIN, TYPE, DATATYPE, AGGREGATE, LINKED, MEMORY, CACHED, LOCAL, GLOBAL, TEMP, TEMPORARY, TABLE, PRIMARY, UNIQUE, HASH, SPATIAL, INDEX"; SQL statement:
Any idea about what going on in the above? Or, can you tell me how I can tell that the DB was auto-created so that I can proceed to create the table?
I don't believe that you're correct when you suggest that you can create a H2 database via SQL - I think that's your basic issue...
Just connect to your DB (and it's the jdbc URL that defines the database involved) and if you don't get an exception, carry on and use it. (Create your table, etc.)
Related
Using the many solutions online I have implemented the following method to check whether the table exists on database or not:
private static boolean tableExists( Connection connection, String schema, String tableName ) throws SQLException {
DatabaseMetaData meta = connection.getMetaData();
ResultSet resultSet = meta.getTables( null, schema, tableName, new String[]{"TABLE"} );
return resultSet.next();
}
This works fine for SQL Server and PostgreSQL, but has a very weird issue with MySQL: if I create two databases that are accessed by the same user, e.g. like this:
create user 'test_user'#'localhost' identified by '123456';
create database first_db;
grant all privileges on first_db.* to 'test_user'#'localhost' with grant option;
create database second_db;
grant all privileges on second_db.* to 'test_user'#'localhost' with grant option;
and add a table for example test_table inside first_db, but do not create it inside second_db (so second_db is empty and first_db has test_table table inside it)
And then make a Connection to the second_db (jdbc:mysql://localhost:3306/second_db) and call my method to see whether it has a table with name test_table (it shouldn't). But the response is true! If I access second_db with another user, the method seems to work correctly though.
Is there something I'm doing wrong? Obviously I can just use separate users if I have multiple databases with the same tables but I would like to understand what causes this behaviour.
I am trying to write java code to migrate data from oracle database to other database.
My use case is that different client have different version of code and so the database columns may vary. Clients with later version have additional column.
For eg : Client with new version as COL99 in the table SAMPLE_TABLE.
While writing the migration code, if I try to select the COL99 from SAMPLE_TABLE, it will work fine for the new client. But for clients on old version, the code fails with
ORA-00904 Invalid Identifier error.
Is there a way to handle in sql query or java code such that, if the column doesn't exist in the database table, simply ignore and do not return the value instead of throwing the exception.
You should first check, whether COL99 exists for your current database connection.
For Oracle you can use a query like this:
SELECT
COL.COLUMN_ID,
COL.OWNER AS SCHEMA_NAME,
COL.TABLE_NAME,
COL.COLUMN_NAME
FROM
SYS.ALL_TAB_COLUMNS COL
INNER JOIN
SYS.ALL_TABLES T
ON COL.OWNER = T.OWNER
AND
COL.TABLE_NAME = T.TABLE_NAME
WHERE
COL.OWNER = 'SCHEMA'
AND
COL.TABLE_NAME = 'SAMPLE_TABLE'
AND
COL.COLUMN_NAME = 'COL99'
Then you create your query with or without COL99.
At the first stage i'm managing my app via JDBC, so i'm the resposible to build and validate all the SQL. But i was wondering if JPA could give me a hand on these tasks.
So, at this moment i've already have a DbaUser model, which was generated from the DBA_USERS table on the OracleDB, and i can actually list all of them.
However, i'm trying to manage to create or update more, but whenever i try to create using
em.createQuery("CREATE USER C##ANTONIO IDENTIFIED BY Antionio123").executeUpdate();
An syntax exception is launched: The query does not start with a valid identifier, has to be either SELECT, UPDATE or DELETE FROM.
Could you guys enlighten me a bit more or pointing me to some proper tutorials? I've been googling but nothing concrete apprears on Oracle DBs system tables.
Update1 (Thanks to #JB Nizet)
After replacing the execution of the query from JPQL to Native SQL, i've got an error such as:
Query: DataModifyQuery(sql="CREATE USER C? IDENTIFIED BY ANTONIO123").
I've replaced the hashtags with a scape character "...C##..." with "...C\#\#..." but the issue earns a different flavour:
Query: DataModifyQuery(sql="CREATE USER C\? IDENTIFIED BY ANTONIO123")
... and i really need to send the "##" to the Oracle DB. How can i force these special characters?
Update 2
So...after googling a bit more, i've found out positional parameters, and i've also discovered that we cannot have named paramteres on JPA native queries. After this, i've tried:
em.createNativeQuery("CREATE USER ?1 IDENTIFIED BY ANTONIO123").setParameter(1, "C##ANTONIO").executeUpdate();
Which triggers: ORA-01935: missing user or role name
alongside with
Error Code: 1935
Call: CREATE USER ? IDENTIFIED BY ANTONIO123
Which tells me that this binding doesn't work. Is there another way to do it?
Kind regards and thanks in advance,
Sammy
createQuery() expects a JPQL query. What you passed is not JPQL. It's SQL.
Use createNativeQuery() to execute SQL.
To create a common user (prefixed with C##) you (i.e. your JPA connection pool user) need a specific priviledges.
CREATE ROLE and
SET CONTAINER
Those are not a typical privileges granted to a JPA connection, so I'm guessing you will fail with the creation of a new common user.
Additionally you need to be connected to the root container.
The further example are plain JDBC called from Groovy, it should be easy possible to pass it to JPA if you get the DB connection.
def stmt = con.prepareStatement("SELECT SYS_CONTEXT('USERENV', 'CON_NAME') CON_NAME FROM dual")
def rs = stmt.executeQuery()
while(rs.next())
{
println "container name= ${rs.getString('CON_NAME')}"
}
gives
container name= CDB$ROOT
Note that if you are connected to a local DB, you get an error while trying to create a user prefixed with C##
ORA-65094: invalid local user or role name
If both conditions are fulfilled, it is possible to create / drop the common user:
String cu = "create user \"C##TEST\" identified by password123 profile \"DEFAULT\" account unlock"
con.createStatement().execute(cu)
resp.
cu = "drop user \"C##TEST\""
con.createStatement().execute(cu)
Finally should be stated, that this exercise was done for the aim of completeness only. I do not see a real use case for a JPA pool connection to be granted such privileges and connecting the root container. The database maintenance is typically done not using JPA.
Another option would be to create a stored procedure in the database and then invoke stored procedure from JPA, thus you do not need to bother about caveats and syntax.
E.g.assume that JPA provider is EclipseLink
Database stored procedure
CREATE OR REPLACE PROCEDURE p_user_creation (p_username IN VARCHAR2,
p_password IN VARCHAR2,
p_return OUT NUMBER)
IS
v_syntax VARCHAR2 (256);
BEGIN
IF (p_username IS NOT NULL)
THEN
v_syntax :=
'CREATE USER '''
|| p_username
|| ''' IDENTIFIED BY '''
|| p_password
|| '''';
EXECUTE IMMEDIATE v_syntax;
p_return := 0;
END IF;
EXCEPTION
WHEN OTHERS
THEN
raise_application_error (-20002, 'An error has occurred!');
END;
Java code snippet to invoke stored procedure
try {
Integer returnValue = null;
StoredProcedureQuery storedProcedureQuery =
getEntityManager().createStoredProcedureQuery("p_user_creation");
storedProcedureQuery.registerStoredProcedureParameter("p_username", String.class, ParameterMode.IN);
storedProcedureQuery.registerStoredProcedureParameter("p_password", String.class, ParameterMode.IN);
storedProcedureQuery.registerStoredProcedureParameter("p_return", Integer.class, ParameterMode.OUT);
storedProcedureQuery.setParameter("p_username", "SCOTT");
storedProcedureQuery.setParameter("p_password", "tiger");
storedProcedureQuery.execute();
returnValue = (Integer) storedProcedureQuery.getOutputParameterValue("p_return");
} catch (Exception e) {
log.error("Error " + e.getMessage());
}
I have 2 different databases one is MYSQL other is Oracle.Each have 1 table with different name and different columns name.Now I have to perform some db opeartions on each db from a single java application.Suppose for MYSQL db I have Emp table with columns Id,Name,Dept and for Oracle db I have Student table with StudentName and StudentDept.Now without changing code how can I manage 2 dbs?If I mention all db connection related data(connection url,username,password) in a properties file but to execute query I have to mention table name and column name in code.How can I manage it dynamically without altering the code so that in future any new db with different table name and column name is added I can only add the new one in properties file and no need to touch the code.Please suggest.
This might not be the prettiest, but one way to do this:
On application launch, parse properties files to get all DB connections. Store these however you want...List of connection pools, list of single connections, list of connection strings, etc...it doesn't matter.
Run a predefined stored procedure or select query to retrieve all table names from each database found in step 1. In sybase you can do this with
select name from sysobjects where type = 'U'
Build a Map where the key is the table name and the value is either the DB name, connection, connection string, or whatever you are using to manage your DB connections from the result set of #2. Anything that can be passed to your DB connection manager to identify which database it should connect to will work as the value.
In code, when table name is passed, lookup the required DB in the map
Execute query on returned DB Info in the map you created in step 3
As long as the tables are distinct in each DB this will work. Once this is setup, new DBs can be added to the properties file and the cache can be refreshed with an application restart. However, if new tables/columns are being sent to the code, how are these being passed without any code change?
I am trying to connect to a SQL Server database, but I don't really know how to go about it using the info I was given. I was given the following:
Provider
DataSource
Persist Security Info
User ID
Initial Catalog
I have always connected via a web address or something, so I didn't really know how to go about using this. I am attempting to do this is Java using JDBC.
See here a wide list of examples, depending on which version you're using:
SQL Server 2000
SQL Server 2005
SQL Server 2008
To connect to MSSQL Server from a Java application, you need to use the JDBC API. The JDBC API provides classes and methods that connect to the database, load the appropriate driver, send SQL queries, retrieve results etc.
HOW TO CONNECT TO THE DATABASE: A ‘Connection’ object represents a connection with a database. To establish the connection, use the method ‘DriverManager.getConnection’. This method takes a string containing a URL which represents the database we are trying to connect to. Below is the sample code for establishing a connection:
private String DATABASE_URL = "jdbc:odbc:embedded_sql_app"; // establish connection to database
Connection connection = DriverManager.getConnection( DATABASE_URL,"sa","123" );
Detailed discussion about the Database URL and how to create it can be found in the resource provided at the end of this post.
QUERYING THE DATABASE: The JDBC API provides three interfaces for sending SQL statements to the database, and corresponding methods in the ‘Connection’ interface create instances of them. 1. Statement - created by the ‘Connection.createStatement’ methods. A ‘Statement’ object is used for sending SQL statements with no parameters.
2. PreparedStatement - created by the ‘Connection.prepareStatement methods’. A ‘PreparedStatement’ object is used for precompiled SQL statements. These can take one or more parameters as input arguments (IN parameters).
3. CallableStatement - created by the ‘Connection.prepareCall’ methods. ‘CallableStatement’ objects are used to execute SQL stored procedures from Java database applications.
RETRIEVING THE RESULT: A ‘ResultSet ‘is a Java object that contains the results of executing a SQL query. The data stored in a ‘ResultSet’ object is retrieved through a set of get methods that allows access to the various columns of the current row. The ‘ResultSet.next’ method is used to move to the next row of the ‘ResultSet’, making it the current row. The following code fragment executes a query that returns a collection of rows, with column ‘a’ as an ‘int’, column ‘b’ as a ‘String’, and column ‘c’ as a ‘float’:
java.sql.Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (rs.next()) { // retrieve and print the values for the current row
int i = rs.getInt("a");
String s = rs.getString("b");
float f = rs.getFloat("c");
System.out.println("ROW = " + i + " " + s + " " + f);
}
This is just a brief introduction on how to interact with a database from Java. For more details on the items discussed above as well as information on passing parameters, executing stored procedures etc. please refer to the following resource: ( http://www.shahriarnk.com/Shahriar-N-K-Research-Embedding-SQL-in-C-Sharp-Java.html#Shahriar_N_Embedding_SQL_in_Java ) Here, you will also find information on how to interact with a database programmatically; i.e. without using SQL. Hope you find this useful.
Source:
http://www.shahriarnk.com/Shahriar-N-K-Research-Embedding-SQL-in-C-Sharp-Java.html