Author Archives: Asaf Tal

How to schedule a job to run on a different hour on a specific date.

Oracle jobs are a simple way to schedule procedure and processes. However, sometimes the scheduling requirements can get really complicated. A very common request is to run a job on a specific hour on weekdays and not to run it on the weekend. This request can be easily delivered using the “WHAT” parameter of the dbms_job.submit procedure.

  IF to_char(sysdate, 'D') BETWEEN 2 AND 6 THEN
      my_procedure ;

However, what will you do if you need to run the procedure at a specific hour on Monday to Friday but on a different hour on the weekend?
In this case you will be happy to know that you can use CASE on the “INTERVAL” parameter of the dbms_job.submit procedure.

  my_job NUMBER;
  dbms_job.submit(job => my_job, 
    what => 'my_procedure ;',
     INTERVAL => 'case
                     when  to_number(to_char(sysdate, ''D'')) between 1 and 5 then 
                        TRUNC(SYSDATE+1) + 16 /24 
                     when  to_number(to_char(sysdate, ''D'')) between 6 and 7 then
                         TRUNC(SYSDATE+1) + 8 /24 

remember that this calculation is for NEXT run not for the current. Therefore, you will need to take into consideration that the timinig for Monday will be calculated on Sunday (I know it sounds obvious but you will be surprised how many time you can do the same mistake).

While the case clause can handle many calculations and complications, there is one caveat. The case statement can handle only 200 characters. This becomes a problem when you try to write a longer statement. For example:

  WHEN  to_number(to_char(sysdate, 'D')) BETWEEN 1 AND 4 THEN 
      TRUNC(SYSDATE+1) + 16 /24 
  WHEN  to_number(to_char(sysdate, 'D'))= 5 THEN
      TRUNC(SYSDATE+1) + 13 /24     
  WHEN  to_number(to_char(sysdate, 'D'))= 6 THEN
      TRUNC(SYSDATE+2) + 16 /24          
      TRUNC(SYSDATE+1) + 16 /24 

if you try to submit a job with this statement, you will probably get the following error

ORA-12899: VALUE too LARGE FOR COLUMN "SYS"."JOB$"."INTERVAL#" (actual: 257, maximum: 200)
ORA-06512: at "SYS.DBMS_IJOB", line 290
ORA-06512: at "SYS.DBMS_JOB", line 159
ORA-06512: at line 4

You can workaround this problem if you use a function to calculate the INTERVAL value.

res DATE;
  WHEN  to_number(to_char(sysdate, 'D')) BETWEEN 1 AND 4 THEN
      TRUNC(SYSDATE+1) + 16 /24
  WHEN  to_number(to_char(sysdate, 'D'))= 5 THEN
      TRUNC(SYSDATE+1) + 13 /24
  WHEN  to_number(to_char(sysdate, 'D'))= 6 THEN
      TRUNC(SYSDATE+2) + 16 /24
      TRUNC(SYSDATE+1) + 16 /24
 INTO res
 FROM dual

once the function is created, all you need to do is use it in your dbms_job submit under the INTERVAL parameter

  my_job NUMBER;
  dbms_job.submit(job => my_job, 
    what => 'my_procedure ;',
    INTERVAL => 'get_next_run_date'

A short reminder – SQLException: Unsupported character set (add orai18n.jar to your classpath)

After upgrading one of our testing environments to a newer oracle version, some of our services started to return the following error:

SQLException: Unsupported character set (add orai18n.jar to your classpath)

From the error message wording, one could suspect that this is an character set but after running


We found out that both databases return the same results.

Therefore, it is obvious that there is a version mismatch between the client and the server. And this message is Oracle’s way of telling you that you need to upgrade your client. Since we are using WebLogic, the process is more complicated.

As suggested, we tried adding the orai18n.jar to the classpath but to no avail.

In addition we discovered that all the problematic service select xmltype from the Database so we assumed that this issue could be solved by some kind of encoding workaround.
We tried converting the character set (convert(col1,’IW8ISO8859P8′,’UTF-8′); ) or tweaking the NLS settings (alter session set nls_territory) only to discover that the simple solution is to convert the xmltype to string and reconverting it back to xmltype

                    XMLELEMENT(  "Field",XMLATTRIBUTES(col_name_1 AS "name") ,col_value_1 ),
                    XMLELEMENT(  "Field",XMLATTRIBUTES(col_name_2 AS "name") ,col_value_2 )
INTO xml --  xmltype 
        'NAME1' AS col_name_1
        ,'VALUE1' AS  col_value_1
        ,'NAME2' AS col_name_2
        ,'VALUE2' AS  col_value_2 
 FROM dual   
RETURN xmltype(to_clob(xml.getStringVal()));

Logstash and Oracle – JDBC input settings

Lately, I began experimenting with elastic search, logstash and kibana. As a DBA, the first thing I wanted to try is Data base connectivity. Just like any new emerging technology, Oracle database is not the first priority on their implementation (and of course, documentation). There are much more examples for sexier (and free) databases like Postgresql or MySQL. As a result, there are only few examples and the configuaration is a real PITA.

While it is easy to find mysql database jdbc for logstash examples

  jdbc {
    jdbc_driver_library => "mysql-connector-java-5.1.36-bin.jar"
    jdbc_driver_class => "com.mysql.jdbc.Driver"
    jdbc_connection_string => "jdbc:mysql://localhost:3306/mydb"
    jdbc_user => "mysql"
    parameters => { "favorite_artist" => "Beethoven" }
    schedule => "* * * * *"
    statement => "SELECT * from songs where artist = :favorite_artist"

It is much harder to find Oracle database jdbc logstash examples but I found something to start with at

jdbc {
      # The path TO our downloaded jdbc driver saved mine IN /bin, driver ojdbc6.jar also works. 
      #Best location can be /vendor folder
           jdbc_driver_library => "ojdbc7.jar"
      # ORACLE Driver Class
           jdbc_driver_class => "Java::oracle.jdbc.driver.OracleDriver"
      # ORACLE jdbc connection string TO our DATABASE, ORACLE  jdbc:oracle:thin:@hostname:PORT/SERVICE
           jdbc_connection_string => "jdbc:oracle:thin:@hostname:PORT/SERVICE"
      # The USER AND password we wish TO EXECUTE our statement AS
           jdbc_user => "DBUSERNAME"
           jdbc_password => "DBPASSWORD"
    # our SQL query
    statement => "select * from AWESOMETABLE"
    #optional extras I USE 
      TYPE => "Database"
      tags => ["awesome", "import"]

Since I did not have ojdbc7.jar on my computer I chose to use ojdbc6.jar so my Oracle database jdbc logstash query came out like this:

jdbc {
    jdbc_connection_string => "jdbc:oracle:thin:@\\my-host:1521:my-sid"
    jdbc_user => "db-user"
    jdbc_password => "db-pwd"
    jdbc_validate_connection => TRUE
    jdbc_driver_library => "C:\path\to\ojdbc6.jar"
    jdbc_driver_class => "Java::oracle.jdbc.driver.OracleDriver"
    statement => "SELECT * from my-table"
output {
elasticsearch {
INDEX => "contacts"
document_type => "contact"
document_id => "%{uid}"
hosts => "localhost:9200"

Along the way, I encountered two error messages that are the reason for this post:
The first

” Error: java::oracle.jdbc.driver.OracleDriver not loaded. Are you sure you’ve included the correct jdbc driver in :jdbc_driver_library?
You may be interested in the ‘–configtest’ flag which you can use to validate logstash’s configuration before you choose to restart a running system. ”

Running the query with the ‘–configtest’ flag did not help much but eventually, it turned out to be a simple typo. The oracle driver was not loaded only because the call was
” java::oracle.jdbc.driver.OracleDriver ” instead of ” Java::oracle.jdbc.driver.OracleDriver “.
(this one was really annoying but I hope this will save you time I spent on it ).

Another message I got along the way was

Java::JavaSql::SQLRecoverableException: IO Error: Invalid connection string fo
rmat, a valid format is: “host:port:sid”

apparently, while all examples for the connection string are in the following format:
The valid format in my case (oracle client 11 on windows 7) was

This should get you connected but if you still get

Java::JavaSql::SQLRecoverableException: IO Error: The Network Adapter could not establish the connection
Check the following:
The database and the listener are running.
The specified port in the code is the same port that the database is listening .
There is no firewall blocking
Good luck

Can you move a table between schemas ?

Many reasons can raise the need to change a table owner or to move a table from one user (schema) to another . regardless of reason, one would expect that Oracle will provide an easy way to move a table to a different schema.

well, the short answer is NO . there is no direct method to change the table owner.

If you try something like

RENAME TABLE_NAME TO new_schema.table_name ;

Oracle Will return ORA-01765: specifying table’s owner name is not allowed
While you can workaround this error by omitting the schema name. However, in our case, this is exactly what we want to do so it is still a problem.

Similarly, the ALTER TABLE command will not do the work as well.

ALTER TABLE source_schema.table_name RENAME TO new_schema.table_name;

While a different error message (ORA-14047: ALTER TABLE|INDEX RENAME May Not Be Combined With Other Operations. ) is returned when trying to use the alter table command to move the table to a different schema, the result is the same.

Another option to move a table to a different user is to simply copy the table using

CREATE TABLE new_schema.table_name AS SELECT  * FROM  source_schema.table_name;

but this will generate a lot of I/O , redo logs and might take a lot of time so it can be a solution only for small tables.
Likewise, Using export and import will require downtime.

While there is no direct method to move a table to a different schema, you can use
One of the less known advantages of partitioning to do the task. the ability to exchange partitions between tables across schema can help us achieve the goal.
Following is the process to move a table from one schema to another:
1) Create a partitioned copy of the table – you do this by using

SELECT dbms_metadata.get_ddl('TABLE','TABLE2MOVE') FROM dual;

if you want just the plain DDL without all the storage definition etc. you can run

       dbms_metadata.set_transform_param dbms_metadata.session_transform,'SEGMENT_ATTRIBUTES',FALSE);

remember to add a partition clause at the end of the ddl

   (	"ID" NUMBER, 
   partition BY hash (id) (partition p1);

2) Exchange the partition between the source and the target table

ALTER TABLE NEW_SCHEMA.table2move exchange partition p1 WITH TABLE SOURCE_SCHEMA.table2move;

3) That’s it! verify it by selecting from the source and target tables

         SELECT * FROM NEW_SCHEMA.table2move;
         SELECT * FROM  SOURCE_SCHEMA.table2move;

One thing to remember is that partitioning is an extra cost option on top of the enterprise edition license. so, if you get ORA-00439: feature not enabled: Partitioning. the option is not enabled. verify it with

SELECT * FROM v$option;

PLS-00801: internal error [string]

apparently, pls-00801: internal error [phdcsql_print_kge_errors::parm pos] is one of the most annoying oracle errors. off course, phdcsql_print_kge_errors::parm pos is just an example that can be replcaed with any other undecipherable set characters.

Oracle’s official error description is:

Cause: This is a generic internal error that might occur during compilation or execution. The first parameter is the internal error number.

Action: Report this error as a bug to your Customer Support representative.

While it might be very tempting to contact Oracle Support, many users will prefer to try and solve the problem without opening a service request and waiting for an answer.
Basically, what this error means is that there is a problem with this query but Oracle is having problem describing the error. The result is a generic (and not really helpful ) error message.
Like any generic error description, many reasons can cause the problem. The only solution is trying to identify the problem yourself by trial and error.

Copy the query part of the code to a separate window and try to tweak it without changing the basics: change tables order, change aliases names, comment what you can or run it without variables. Even if this will not solve the problem, sometimes this can provide a more informative error message.
Using this method I have found several issues that caused pls-00801 internal error. I am writing a few in order to provide some list of things that can cause this error:

1) The query used a remote database using a db link and the database link user did not have proper permissions.
2) Extra not visible control characters that were added to the code during a problematic copy-paste from the web or from Word.
3) Extra characters that might have different meaning in oracle like:&,”,_ etc.
4) Extra spaces
5) Invalid objects on remote database
6) Several known Oracle bugs (search metalink for the error)
7) An error on a remote database can not be displayed.
8) Your entry here …

Of course, there are countless other reasons for pls-00801. If you encounter any other reason please share it in the comments to help others.