I've written some Java code to use JDBC to copy the contents of a table from one DB to another (it requires that the table exist in both DBs, it does not check the target table for the existence of any of the data it's copying over).
It uses PreparedStatements, and copies in blocks of 10,000. I would like to add the ability to disable all indexes / foreign key constraints, and then re-enable them when the table has been completely copied over.
Is there a way to do this using pure JDBC, i.e. not just firing over some vendor specific code?
There is nothing in JDBC itself that provides such functionality. You will need to use database specific functionality to do this.
Short answer: no, there isn't.
Longer answer:
Given a java.sql.Connection theConnection:
DatabaseMetaData metaData = theConnection.getMetaData ();
String dbType = metaData.getDatabaseProductName ();
String command;
for "MySQL":
command = "ALTER TABLE <tableName> [ENABLE | DISABLE] KEYS;"
for "Microsoft SQL Server":
command = "ALTER INDEX ALL ON <tableName> [REBUILD | DISABLE];"
(feel encouraged to add other DB commands below.) Once you have command, execute it
Statement stmt = theConnection.createStatement ();
stmt.execute (command);
Related
Database : Oracle 12c (12.1.0.2) - Enterprise Edition with RAC
I'm trying to reduce REDO and archive logs generated for my application and measure using V$SYSSTAT and corresponding archive logs using DBA_HIST* views.
In my application code on DB side, I'm using the session level setting of TEMP_UNDO_ENABLED to direct UNDO for gtt into temporary tablespace. The specific feature noted here.
ALTER SESSION SET TEMP_UNDO_ENABLED = TRUE;
INSERT INTO my_gtt VALUES...
Note the documentation has this quote:
..if the session already has temporary objects using regular undo, setting this parameter will have no effect
If I use a pure database session, I can ascertain that since no other temporary tables have been created/used before setting the parameter, the REDO logs generated are minimal. I can use a simple (select value from V$SYSSTAT where name= 'redo size') to see the difference.
However the actual application (Java) triggers this code through a JDBC session. As such, I'm unable to ascertain if before the call to 'ALTER SESSION..' there were any GTT or other temporary objects previously created/used in the session. The consequence of this is, if say a GTT was already used, then the call to 'ALTER SESSION SET TEMP_UNDO_ENABLED = TRUE' simply ignores the setting without an indication. The code will continue logging UNDO & REDO in the normal tablespace, which is unintended.
Is there any way to query if this parameter TEMP_UNDO_ENABLED is already set/unset within the session, so that before I do a ALTER SESSION SET TEMP_UNDO_ENABLED = TRUE I'll know for sure this will or will not have an effect?
Thanks in advance for inputs.
There is no holistic way to do this satisfying all cases. Posting some options I got as answer elsewhere:
Assumptions :
Both options work only if:
Only GTT is concerned (excluding WITH and other temporary objects)
COMMIT/ROLLBACK has not already been done including from SAVEPOINTS
or other methods
Option 1 : Use v$tempseg_usage, to check if any segment created in DATA, instead of TEMP_UNDO
select count(*)
from v$tempseg_usage
where contents = 'TEMPORARY'
and segtype = 'DATA'
and session_addr =
(select saddr
from v$session
where sid = sys_context('userenv', 'sid'));
Option 2 : Use gv$transaction as below, ubafil = 0 if for temp_undo, else ubafil = undo tablespace file id:
select count(*)
from gv$transaction
where ses_addr = (select saddr
from v$session
where sid = sys_context('userenv', 'sid'))
and ubafil <> 0;
On other note for thought, I still think, there should have been a parameter or an indication elsewhere that simply indicates the setting of TEMP_UNDO_ENABLED has not had an effect, within the scope of a SESSION, not having to touch views that would otherwise be considered as administrative.
I'm open to answers if someone finds a better approach.
Although this does not answer your question directly but this link may help you.
In 12c temporary undo concept has been added
" Oracle 12c introduced the concept of Temporary Undo, allowing the
undo for a GTT to be written to the temporary tablespace, thereby
reducing undo and redo."
We are migrating our codebase from Delphi XE3 with FireDAC 8.0.5 to Delphi Berlin 10.1 Upd 2 with FireDAC 15.0.1 (Build 86746). Everything is working smoothly using MS Sql Server, but using ORACLE it has been another history.
Throughout the application source code we use lots of TAdQuery with sql instructions like
AdQuery1.Sql.Text := 'SELECT FIELD1, FIELD2 FROM TABLE1';
In order to insert a record, we use Append or Insert methods, like this
AdQuery1.Insert;
//or
AdQuery1.Append;
Just after invoking its Post method, the component internally creates an INSERT sql statement, that goes like this
INSERT INTO TABLE1 (FIELD1, FIELD2) VALUES(:FIELD1, :FIELD2)
So the record gets inserted successfully.
Now, using TFdQuery in Delphi Berlin, the component internally creates an INSERT sql statement, like this
INSERT INTO USERNAME.TABLE1 (FIELD1, FIELD2) VALUES(:FIELD1, :FIELD2)
Failing with a [FireDAC][Phys][Ora] ORA-00942: table or view does not exist
This happens because in our Oracle database, TABLE1 is created in a schema called MAIN_SCHEMA, and we access it by using a public synonym.
Trying to find a workaround, we compared FireDAC source code, finding that
in Delphi XE3, the unit uADDAptManager.pas, on its function TADDAptTableAdapter.GetUpdateRowCommand, calls oConn.CreateCommandGenerator(oCmdGen, nil);
in Delphi Berlin, the unit FireDAC.DApt.pas, on its function TFDDAptTableAdapter.GetUpdateRowCommand
calls oConn.CreateCommandGenerator(oCmdGen, GetSelectCommand);
Whenever that second parameter (called ACommand: IFDPhysCommand) is not nil, the name of the table is returned concatenating the user name (in a function called TFDPhysCommandGenerator.GetFrom).
If we add 'MetaCurSchema=MAIN_SCHEMA' to the TFdConnection params, it works with the applications that not use a pooled connection, but We have several process that use a pooled connection with the same params, even MetaCurSchema param, but it doesn't work
What can we do?
thanks for your help
What I understand is that you would do better making the connection avoid the use of any schema name, rather than specifying it. Also, keeping in mind that you already use public synonyms.
So, according to the documentation:
Full object names
FireDAC supports full object names, which include the catalog and/or schema names.
When a short object name is specified to StoredProcName, TableName, etc, they will be expanded into the full object names, using the current catalog and/or schema names. To override or avoid usage of the current catalog and/or schema names, use the MetaCurCatalog and MetaCurSchema connection definition parameters. For example:
[Oracle_Demo]
DriverID=Ora
...
MetaCurCatalog=*
MetaCurSchema=*
~ Source: Object Names (FireDAC) - docWiki
MetaCurSchema
Specifies the current schema for the application. If not specified, then its value will be received from the DBMS. When an application is asking for metadata and do not specify a schema name, then FireDAC will implicitly use the current schema.
If MetaCurSchema is '*', then schema names will be me omitted from the metadata parameters.
~ Source: Common Connection Parameters (FireDAC) - docWiki
That asterisk (*) should do the trick, let us know if that's the case.
I try to backup the tables content of a H2 DB.
I run : SCRIPT TO '/opt/data/2019-10-10_tr.sql' TABLE EVENEMENT, PASSAGE, COURSE, LIGNE but the file generated contains some information like :
SET DB_CLOSE_DELAY -1;
;
CREATE USER IF NOT EXISTS SA SALT '7ab09337026fac20' HASH 'c...fa387' ADMIN;
CREATE SEQUENCE PUBLIC.HIBERNATE_SEQUENCE START WITH 5664;
CREATE MEMORY TABLE PUBLIC.COURSE(
...
Which I don't want (that's why I wanted to dump only the tables). I don't want them because when I run RUNSCRIPT FROM '/opt/data/2019-10-10_tr.sql' I have an exception :
CREATE SEQUENCE PUBLIC.HIBERNATE_SEQUENCE START WITH 5664 [90035-197]: org.h2.jdbc.JdbcSQLException: Sequence "HIBERNATE_SEQUENCE" already exists; SQL statement:
CREATE SEQUENCE PUBLIC.HIBERNATE_SEQUENCE START WITH 5664 [90035-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
And I have this exception because the database is initialized by ddl : <property name="hibernate.hbm2ddl.auto" value="create-drop" />
I don't wish to change this ; basically by saving only database content and restore it in an existing db : it should work, isn't it ? So the question is what is wrong with my SCRIPT syntax though it doesn't save the tables content only ?
SCRIPT command is not designed to export only the data, it is designed to export the schema with or without the data. Currently there is no built-in command for that purpose.
You can try to add the ˙DROP˙ clause to this command to generate commands for dropping existing tables, but you still may have a problem with sequences and your tables will be redefined, so all changes in autogenerated schema will be lost.
You can filter out all non-INSERT commands from the script with your own code.
You can export the complete script and execute DROP ALL OBJECTS before RUNSCRIPT and overwrite everything with it.
I need to create auditing tables in Oracle using a Loading Knowledge Module (LKM).
Knowledge Modules typically create various tables, triggers and views which are named dynamically, e.g.: C$_tablename, J$_tablename, T$_tablename, JV$_tablename, etc. etc.
I would like to do something similar for my auditing tables, i.e. all audit tables would be called "tablename_audit", but do not how to set this up in the LKM code.
As an example, the following LKM code is used to create a C$ work table:
create table <%=odiRef.getTable("L", "COLL_NAME", "A")%>
(
<%=odiRef.getColList("", "[CX_COL_NAME]\t[DEST_WRI_DT] NULL", ",\n\t", "","")%>
)
And the following IKM code creates an I$ flow table:
create table <%=odiRef.getTable("L", "INT_NAME", "W")%>
(
<%=odiRef.getColList("", "[COL_NAME]\t[DEST_WRI_DT] NULL", ",\n\t", "", "")%>
,IND_UPDATE char(1)
)
INT_NAME and COLL_NAME seem to be constants defined in the Substitution API, as specified here.
So, how can I use the knowledge module to create similar tables with dynamic names in an Oracle Database?
Thank you.
I managed to solve this as follows.
<%=odiRef.getTable("L", "TARG_NAME", "A")%> returns the target table name in DATABASE."tablename" format.
I therefore added a step to my LKM which uses Jython to extract the tablename from the DATABASE."tablename" string, append "_audit" to the table name, and then save the DATABASE."tablename_audit" string to a Jython variable, as shown below.
targTableName = '<%=odiRef.getTable("L", "TARG_NAME", "A")%>'
splitStr = targTableName.split('"')
JYTHON_AUDIT_TABLE = splitStr[0] + '\"' + splitStr[1] + '_audit\"'
However, since Jython variables cannot be used from SQL scripts in ODI, I added another step to my LKM which fetches the Jython variable into a Java variable (which can then be used by ODI objects) using ODI Expert's Jython to Java API.
import api.getInfo as info;
info.setJythonVariable(JYTHON_AUDIT_TABLE);
<#
import api.getInfo;
String JAVA_AUDIT_TABLE = getInfo.getJythonVariable();
#>
I could then easily use the JAVA_AUDIT_TABLE variable in my SQL scripts to create the required tables in my target database.
create table <#=JAVA_AUDIT_TABLE#>...
insert into <#=JAVA_AUDIT_TABLE#>...
I am in a similar situation but with columns. I followed your steps and I am running into error when setting up the java variable. I might not be using the correct technology or doing something stupid.
I used Java bean shell technology in command on source and used the code snippet you provided.
It would be really helpful if you could you please provide more information like technology you used in command on source and target.
Can any one give me the syntax to truncate a table in IBM DB2.
I m running the following command: truncate table tableName immediate;
The eror is DB2
SQLCODE=-104, SQLSTATE=42601, SQLERRMC=table;truncate ;JOIN , DRIVER=3.50.152
Message: An unexpected token "table" was found following "truncate ". Expected tokens may include: "JOIN ".. SQLCODE=-104, SQLSTATE=42601, DRIVER=3.50.152
The syntax matches the one specified in the reference docs of IBM : http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.sqlref/db2z_sql_truncate.htm
There is a great article about truncating, here is the Gist of DB2 stuff
Almost follows the standard.(since version 9.7)
DB2 requires that the IMMEDIATE keyword be added the the ordinary TRUNCATE TABLE statement, e.g.:
TRUNCATE TABLE someschema.sometable IMMEDIATE
TRUNCATE TABLE must be the first statement in a transaction. A transaction starting with TRUNCATE TABLE may include other statements, but if the transaction is rolled back, the TRUNCATE TABLE operation is not undone.
DB2s TRUNCATE TABLE operation has a number of optional arguments, see the documentation for more on this; especially, the REUSE STORAGE argument may be important for ad-hoc DBA tasks.
In DB2 versions < 9.7, you may abuse the IMPORT statement. Unfortunately, you need to know which operating system the command is executed from for this to work:
On unix-like systems:
IMPORT FROM /dev/null OF DEL REPLACE INTO tablename
On Windows:
IMPORT FROM NUL OF DEL REPLACE INTO tablename
IMPORT cannot be abused in all contexts. E.g., when working with dynamic SQL (from Java/.NET/PHP/...—not using the db2 command line processor), you need to wrap the IMPORT command in a call to ADMIN_CMD, e.g.:
CALL ADMIN_CMD('IMPORT FROM /dev/null OF DEL REPLACE INTO tablename')
IMPORT seems to be allowed in a transaction involving other operations, however it implies an immediate COMMIT operation.
The ALTER TABLE command may also be abused to quickly empty a table, but it requires more privileges, and may cause trouble with rollforward recovery.
This was taken from the website:
http://troels.arvin.dk/db/rdbms/#bulk-truncate_table-db2
If you are using DB2 for AS400, IMMEDIATE TRUNCATE TABLE will NOT work. The equivallent work around is to either:
DELETE FROM [tableName] then if it is an auto increment equivalant column, run:
ALTER TABLE ALTER COLUMN RESTART WITH 1
OR the faster (most efficient way)
Pass a command to the system to clear out the Physical File
Java syntax:
CommandCall command = new CommandCall(new AS400(AS400SystemName, AS400JavaUser, AS400JavaPwd));
try {
command.run("CLRPFM FILE(as400SchemaName/" + tableName + ")");
Which version of DB2 are you using? The truncate table command was introduced in DB2 v9 (at least on the mainframe, which appears to be what you're asking about based on the link).
You may have to resort to the delete from option although this article gives a stored procedure way of doing it in DB2 v8.
use truncate 'table_name' immediate
This is the exact reference documentation available for TRUNCATE in DB2 from 9.7 version
DB2 Reference for TRUNCATE
DB2 on z/OS V10
Empty one of your tables: truncate table; followed by commit work. Ex. truncate temp;
Someone else table: truncate owner.table Ex: truncate student.work ;
I have not tried this on a linked DB2. I do not know if truncate node2.student.work; is good.
SQL for creating list of tables automatically. Substring (substr) used because column width for table name and creator are sooo long. Your values may be different.
select 'truncate table '||substr(creator,1,9)||'.'||substr(name,1,20)
from sysibm.systables
where creator = 'Student';
in Java make sure it's the first statement in the transaction