I have an embeded derbyDB in my app, and I am currently testing my code.
If I send the following SQL code
set current schema [newSchemaName];
from ij then I can set the schema and the response from the DB of
show tables;
will report only the tables that exist in the newSchemaName previously identified (although this doesn't always seem to work!)
If I do a similar thing from java code and then perform a
getCurrentConection.getSchema();
The value returned from the above never proposes the newSchemaName passed in the SQL (although if I use a prepared statement it returns the newSchemaName as expected).
Here is some extra background info...
I have the default database name 'derbyTest' and create 3 other schemas.
Admin
S1
S2
to logically separate/hide information from users that they don't need to know about
I need to change schemas during operation (eg: an admin will change schemas if required to view more 'delicate' info).
To do this I created a method for setSchema(String newSchemaName), that creates the schema (if it doesn't already exist) then connects to it.
However after running the code snippet
/**
*method to change to a given schema
*#param newSchemaName the new schema to change to
/
public void SetSchema(String newSchemaName){
String sql = newSchemaName.toUpperCase();//make sure the newSchemaName is in upper case.
ResultSet rs;
try
{
rs = this.sendQry("select schemaName from sys.sysschemas where schemaname = '" + sql + "'");//does this schema exist in the DB
if (rs.next())
{//the schema already exists
//send some messages to the user about the change of schema
errLog.setDevError(1, "derbyDB schema" +sql +" already exists ");
errLog.add(2, "connecting to " + sql);
//next line create the SQL for changing to the newSchemaName supplied
this.sendSQL("set current schema " + sql);//connect to the schema
//log a message to display the current schema in the DB
//this next log never shows a change to the newSchemaName unless
//I use a prepared statement in my java code.
errLog.add(1, "current DB schema is " + getCurrentConection.getSchema();
}
else{//the schema does not exist
//send a message to the user and output log
errLog.setDevError(1, "derbyDB schema" +sql +" does not exist ");
//code to send message asking if user wants to create the new schema....
}
}//end try
catch{
//catch errors
}
}//end method
If I look at the docs http://db.apache.org/derby/docs/dev/ref/rrefsqlj32268.html for setting the schema my SQL is correct, and the code works if I run directly from ij.
I know that there are some differences between ij and the client side (functions such as describe don't work in the client, you need to fart about with meta data instead).
Is it the same case for the set schema statment. Or does this only work from a prepared statement, which I'm about to test.
If so that begs the question of why I can only change the schema from a prepared statement?
Thoughts and comments greatefully accepted.
David
edit:
A prepared statement works for changing the schema. so now it is only the second question that stands. why the difference between a prepared statement and a normal statement... time for google I think?
edit:
I don't know if it would make a difference but I am on a windows platform, using the standard JDK (6), and eclipse indigo running jUnit test inside eclipse. I can also test on Linux(ubuntu) with opendJDK if it may help to troubleshoot.
I'm not sure what your question is.
You can specify the schema explicitly in your table references, as in:
SELECT * FROM S1.TABLE_NAME
or
UPDATE S2.TABLE_NAME SET COL1=VALUE1
etc.
Or, if you prefer, you can omit the schema name from your table references, saying merely:
SELECT * FROM TABLE_NAME
or
UPDATE TABLE_NAME SET COL1=VALUE1
etc., in which case you will need to establish an implicit schema for those statements, either by issuing a SET SCHEMA statement, or by using the existing default schema, which matches your username when you log in.
I think your question about prepared statements versus non-prepared statements has to do with the fact that, if you don't specify an explicit schema, then the default schema name is established when the statement is prepared.
If it were me, and I cared about what schema I was using, I would specify the schema explicitly in all my table references in all my SQL statements, and then I'd be sure which schema I was using when.
Related
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.
I'm trying to convert a MySQL stored procedure to java code. It's pretty simple SQL. It creates three temporary tables and then does a select based on them. However, I'm having trouble with SQLWarnings related to Data Truncation being thrown while creating the last temp table.
I'm not looking for an explanation of the warnings themselves. I was getting the same warnings during execution of the stored procedure (due to improperly formatted datetime fields), only there it didn't cause me any problems. In the java version, after Statement.executeUpdate() throws an SQLWarning, the temp table I was attempting to create doesn't exist.
How can I suppress the SQLWarnings? I'd prefer to be able to log a message noting the warning text, but I want my temp table to successfully be created as well.
My code looks something like this:
sqlStatement = "create temporary table mytemptable as (select ...) ;";
try {
stmt.executeUpdate(sqlStatement);
// Throws SQLWarning about Data Truncation
} catch (SQLWarning sqlW) {
logInfo("SQLWarning Caught: " + sqlW.getMessage());
}
stmt.executeQuery("select * from mytemptable ");
// Throws SQLException because mytemptable doesn't exist
To me it's a little strange but the equivalent of this worked:
create temporary table mytemptable ignore select ...;
This way, no exception is thrown by jdbc, but you can still call getWarnings() on the Statement object to get a list of warnings that were ignored.
Thanks Norbert van Nobelen for helping me figure this out in the comments of the OP.
I have a a project name drop-down list, and based on the selected value a schema drop-down list is generated.
After the schema list is generated, there is a 'choose file' option where a script name is chosen which is to be run on multiple schemas.
Both the project list values and the schema list values are stored in the database. There is another table in the database where the schema credentials are stored.
I want to know that how create connections on those multiple schemas, and how to run a script in multiple schemas selected from that schema drop-down list.
I have executed the code in one schema using iBatis framework using scriptrunner method.
Table 1: ProjectName
PROJECT_PK,
PROJECT_CODE,
PROJECT_NAME
Table2: ComponentName
COMPONENT_PK,
COMPONENT_CODE,
COMPONENT_NAME,
PROJECT_PK
Table 3: SchemaName (This table contains the credentials of Other Schemas)
SCHEMA_PK,
SCHEMA_NAME,
PASSWORD,
ORACLE_SID,
HOST_NAME,
PORT_ID
Table 4: PROJECT_DETAIL
PROJECT_DETAIL_PK,
COMPONENT_PK,
SCHEMA_PK
Table5: COMPONENT_DETAILS
COMPONENT_DETAILS_PK,
PROJECT_PK,
SCHEMA_PK
I am attaching the scenario image.
I propose you create a 'super-schema' with the appropiate grants on every other schema, and create your JDBC connection for this 'super-schema'. This will make you need some tampering with the sql script - you will need to write it with some marker to easily substitute the schema, something like
ALTER TABLE ${SCHEMA_MARKER}.INVOICES ADD CLIENT_ADRRESS Varchar2(35);
And your java code would substitute it for the schema you are targeting. With some imagination you can extend this idea to execute bulk DDL scripts on all your schemas.
By the way, I understand by your question that you have many schemas with the same structure. I was forced once to work with such a legacy structure, and so I know there is a lot of momentum in corporate structures; nonetheless I must recommend you to redesign such system. Think for example in creating materialized views on your super-schema, replicating your schema structure but with a new field in every table primary key (this new field would fill the gap that made whomever did it separe the data in many schemas for starters).
This will surely make your query cache suffer a lot less, and will make easier the development of any new software that needs to work with that 'distributed' data.
In Oracle, a schema is basically a user. So to create a table FOO in the schema SX, you just login as user SX and execute create table FOO (...) (without specifying a schema). The user == schema convention in Oracle will make sure this works.
To login as user SX, get hold of your DataSource and use getConnection(String username, String password) instead of the default getConnection()
Alternative ways are to add placeholders in your script that you process to generate valid SQL first. See the answer by Jorge_B for an example.
Lastly, you can change the default schema using ALTER SESSION (see Default Schema in Oracle Connection URL). The problem with this approach is that you must restore the schema before closing the connection when using a web container with a DataSource - in this scenario, connections are never really closed, so the next piece of code asking for a connection will get one with an unexpected default schema -> hard to find errors.
Here is the DAO class to create multiple schema connection on the same database at run time.
We need to enter the schema names at run time through and call that in some servlet.
The schema details i.e username, password,host Id,port Id and SID are to be stored in the database tables though which the connections will be created.
The created connections are stored here in the list which can be used at a later point of time.
The credential DTO here is the object which maps to the database tables in the database and then
Connection conn=DBUtil.getConnection(constants.DB_DS_NAME);
Statement stmt=null;
stmt=conn.createStatement();
ResultSet rs= null;
Connection [] con=new Connection[schemaname.length];
int i,j;
String [] url=new String[schemaname.length];
String [] username=new String[schemaname.length];
String [] password=new String[schemaname.length];
List<CredentialDTO> creDTOlist=new ArrayList<CredentialDTO>();
String query1="insert into dba_project_master VALUES(9,'abc','abc','abc','abc',40)";
String query2="CREATE TABLE EMP(EMPNO NUMBER(4,0) NOT NULL ENABLE,ENAME VARCHAR2(10 BYTE),JOB VARCHAR2(9 BYTE), SAL NUMBER(7,2),DEPTNO NUMBER(2,0))";
try
{
for(i=0;i<schemaname.length;i++){
String query=" select * from dba_schema_details where schema_name="+DBUtil.enquoteString(schemaname[i]);
rs=stmt.executeQuery(query);
while(rs.next()){
CredentialDTO creDTO=new CredentialDTO();
creDTO.setSCHEMA_PK(rs.getString("SCHEMA_PK"));
creDTO.setSCHEMA_NAME(rs.getString("SCHEMA_NAME"));
creDTO.setPASSWORD(rs.getString("PASSWORD"));
creDTO.setORACLE_SID(rs.getString("ORACLE_SID"));
creDTO.setHOST_NAME(rs.getString("HOST_NAME"));
creDTO.setPORT_ID(rs.getString("PORT_ID"));
creDTOlist.add(creDTO);
}
}
System.out.println("creDTOlist size:"+creDTOlist.size());
//create URL for the schema name
int m=creDTOlist.size();
Iterator<CredentialDTO> LItr= creDTOlist.iterator();
String [] username1=new String[m];
String [] password1=new String[m];
i=0;
while(LItr.hasNext()){
System.out.println("iteration "+i);
CredentialDTO temp = LItr.next();
String URL="jdbc:oracle:thin:#"+temp.getHOST_NAME()+":"+temp.getPORT_ID()+":"+temp.getORACLE_SID();
System.out.println("URL:"+URL);
username1[i]=temp.getSCHEMA_NAME();
System.out.println("iteartion "+i+" username="+username1[i]);
password1[i]=temp.getPASSWORD();
System.out.println("iteartion "+i+" password="+password1[i]);
Class.forName("oracle.jdbc.OracleDriver");
con[i]=DriverManager.getConnection(URL, username1[i], password1[i]);
System.out.println("Connection Name:" +con[i]);
Statement st1=con[i].createStatement();
con[i].setAutoCommit(false);
st1.addBatch(query1);
st1.addBatch(query2);
int [] update=st1.executeBatch();
i++;
}
}
catch(Exception ex){
ex.printStackTrace();
}finally
{
if (conn != null) try{conn.close();} catch(SQLException ignore) {}
if (stmt!= null) try{stmt.close();} catch(SQLException ignore) {}
if (rs != null) try{rs.close();} catch(SQLException ignore) {}
}
return creDTOlist;
}
}
When doing...
select * from students
I get a "Invalid object name" error. Basically, I think I can see the problem in that the tables are prefixed with an object name rather than just dbo, lets call the schema "test".
So this means....
select * from test.students
The problem I have is that I can't change the SQL code (it's in release, long story) or change the tables. My question is, is there anything I can change in SQL server that will allow me to connect say with a specific SQL server user so I can still run my queries as...
select * from students
Omitting the object name, but still have the object name against the table? I can add another SQL user or something like that no problem.
I'm using Java over the jdbc protocol, so my connection string is something like jdbc:sqlserver://hostname:port;databaseName=db;user=myuser;password=mypassword
Thanks,
David
You're looking for a default schema option, which doesn't exist for a given connection. That is to say that you can't say something like "until I say otherwise, unqualified tables are in the test schema". You can, however, set a default schema for a user. For your example, you'd do
alter user [myuser] with default_schema = [test]
Try to edit the connection string and set your default catalog to your "test" database
<add name="ConnectionString" connectionString="Data Source=server;Initial
Catalog=test;Persist Security Info=True;User ID=user;Password=password;"
providerName="SqlDataClient"/>
I am getting below exception, when trying to insert a batch of rows to an existing table
ORA-00942: table or view does not exist
I can confirm that the table exists in db and I can insert data to that table using oracle
sql developer. But when I try to insert rows using preparedstatement in java, its throwing table does not exist error.
Please find the stack trace of error below
java.sql.SQLException: ORA-00942: table or view does not exist
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:573)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1889)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1093)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2047)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:1940)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout>>(OracleStatement.java:2709)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:589)
at quotecopy.DbConnection.insertIntoDestinationDb(DbConnection.java:591)
at quotecopy.QuoteCopier.main(QuoteCopier.java:72)
Can anyone suggest the reasons for this error ?
Update : Issue solved
There was no problem with my database connection properties or with my table or view name. The solution to the problem was very strange. One of the columns that I was trying insert was of Clob type. As I had a lot of trouble handling clob data in oracle db before, gave a try by replacing the clob setter with a temporary string setter and the same code executed with out any problems and all the rows were correctly inserted!!!.
ie. peparedstatement.setClob(columnIndex, clob)
was replaced with
peparedstatement.setString(columnIndex, "String")
Why an error table or view does exist error was throws for error in inserting clob data. Could anyone of you please explain ?
Thanks a lot for your answers and comments.
Oracle will also report this error if the table exists, but you don't have any privileges on it. So if you are sure that the table is there, check the grants.
There seems to be some issue with setCLOB() that causes an ORA-00942 under some circumstances when the target table does exist and is correctly privileged. I'm having this exact issue now, I can make the ORA-00942 go away by simply not binding the CLOB into the same table.
I've tried setClob() with a java.sql.Clob and setCLOB() with an oracle.jdbc.CLOB but with the same result.
As you say, if you bind as a string the problem goes away - but this then limits your data size to 4k.
From testing it seems to be triggered when a transaction is open on the session prior to binding the CLOB. I'll feed back when I've solved this...checking Oracle support.
There was no problem with my database connection properties or with my table or view name. The solution to the problem was very strange. One of the columns that I was trying insert was of Clob type. As I had a lot of trouble handling clob data in oracle db before, gave a try by replacing the clob setter with a temporary string setter and the same code executed with out any problems and all the rows were correctly inserted!!!.
ie. peparedstatement.setClob(columnIndex, clob)
was replaced with
peparedstatement.setString(columnIndex, "String")
#unbeli is right. Not having appropriate grants on a table will result in this error. For what it's worth, I recently experienced this. I was experiencing the exact problem that you described, I could execute insert statements through sql developer but would fail when using hibernate. I finally realized that my code was doing more than the obvious insert. Inserting into other tables that did not have appropriate grants. Adjusting grant privileges solved this for me.
Note: Don't have reputation to comment, otherwise this may have been a comment.
We experienced this issue on a BLOB column. Just in case anyone else lands on this question when encountering this error, here is how we resolved the issue:
We started out with this:
preparedStatement.setBlob(parameterIndex, resultSet.getBlob(columnName)); break;
We resolved the issue by changing that line to this:
java.sql.Blob blob = resultSet.getBlob(columnName);
if (blob != null) {
java.io.InputStream blobData = blob.getBinaryStream();
preparedStatement.setBinaryStream(parameterIndex, blobData);
} else {
preparedStatement.setBinaryStream(parameterIndex, null);
}
I found how to solve this problem without using JDBC's setString() method which limits the data to 4K.
What you need to do is to use preparedStatement.setClob(int parameterIndex, Reader reader). At least this is what that worked for me. Thought Oracle drivers converts data to character stream to insert, seems like not. Or something specific causing an error.
Using a characterStream seems to work for me. I am reading tables from one db and writing to another one using jdbc. And i was getting table not found error just like it is mentioned above. So this is how i solved the problem:
case Types.CLOB: //Using a switch statement for all columns, this is for CLOB columns
Clob clobData = resultSet.getClob(columnIndex); // The source db
if (clobData != null) {
preparedStatement.setClob(columnIndex, clobData.getCharacterStream());
} else {
preparedStatement.setClob(columnIndex, clobData);
}
clobData = null;
return;
All good now.
Is your script providing the schema name, or do you rely on the user logged into the database to select the default schema?
It might be that you do not name the schema and that you perform your batch with a system user instead of the schema user resulting in the wrong execution context for a script that would work fine if executed by the user that has the target schema set as default schema. Your best action would be to include the schema name in the insert statements:
INSERT INTO myschema.mytable (mycolums) VALUES ('myvalue')
update: Do you try to bind the table name as bound value in your prepared statement? That won't work.
It works for me:
Clob clob1;
while (rs.next()) {
rs.setString(1, rs.getString("FIELD_1"));
clob1 = rs.getClob("CLOB1");
if (clob1 != null) {
sta.setClob(2, clob1.getCharacterStream());
} else {
sta.setClob(2, clob1);
}
clob1 = null;
sta.setString(3, rs.getString("FIELD_3"));
}
Is it possible that you are doing INSERT for VARCHAR but doing an INSERT then an UPDATE for CLOB?
If so, you'll need to grant UPDATE permissions to the table in addition to INSERT.
See https://stackoverflow.com/a/64352414/1089967
Here I got the solution for the question. The problem is on glass fish if you are using it. When you create JNDI name make sure pool name is correct and pool name is the name of connection pool name that you are created.