3

I am trying to execute a SQL script (read from a file) on an Oracle database. I have tried many methods but none are working.

I have the following method:

def connect_cx_oracle():

    dns_tns = cx_Oracle.makedsn(config.DB_HOST, config.DB_PORT, service_name=config.DB_DBASE)
    con = cx_Oracle.connect(user=config.DB_USERNAME, password=config.DB_PASSWORD, dsn=dns_tns)
    cur = con.cursor()

    fd = open('PurgeProcess_2.sql')
    full_sql = fd.read()
    cur.prepare(full_sql)
    cur.executemany(None, full_sql)
    con.commit()

Using cur.execute on the file results in an error. I can't split the file with semi colons since it's a script.

The code for the sql file is something like this (not posting entire file)

SET SERVEROUTPUT ON SIZE UNLIMITED;
DECLARE

    CURSOR c_task IS SELECT job_id, task_info_id FROM task WHERE job_id <= myjob_id;

BEGIN

  dbms_output.ENABLE(NULL);
  dbms_output.put_line('*******************************');
  dbms_output.put_line('* Purge job started.......     ');
  dbms_output.put_line('*******************************');

        IF (FROM_date < 30) THEN
            dbms_output.put_line(' ');

        end IF;
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            dbms_output.put_line(' ');
            dbms_output.put_line('*******************************');
            dbms_output.put_line('* Purge job completed.......   ');
            dbms_output.put_line('*******************************');
            RAISE NO_ITEMS_TO_PROCESS;
    END;

    FOR i IN 1..myjobIDnumber.COUNT
    LOOP
        BEGIN
            DELETE FROM job WHERE id = myjobIDnumber(i);
            IF SQL%ROWCOUNT > 0 THEN
                deletecount4 := deletecount4 + SQL%ROWCOUNT;
            END IF;
        END;
    END LOOP;

    dbms_output.put_line('Job table records deleted. Number of records deleted is ' || deletecount4);
    dbms_output.put_line(' ');

    ROLLBACK;
    --COMMIT;

    dbms_output.put_line('*******************************');
    dbms_output.put_line('* Purge job completed.......  *');
    dbms_output.put_line('*******************************');
EXCEPTION
    WHEN NO_ITEMS_TO_PROCESS THEN
    NULL;
    WHEN DATE_LIMIT_APPROACHED THEN
    NULL;
END;

If I use cur.execute(fileName) I get

cx_Oracle.DatabaseError: ORA-00922: missing or invalid option

With executemany I get

TypeError: parameters should be a list of sequences/dictionaries or an integer specifying the number of times to execute the statement

I am not really a sql guy, any help would be appreciate. Regards

2 Answers 2

2

cx_Oracle and other similar drivers can only execute one statement at a time. Even executemany() executes one statement (but with many data values).

The simplest way to do what you want is to:

  • strip out all SQL*Plus-specific commands like SET from your SQL file since the DB won't understand them if cx_Oracle tries to execute them. And they mean nothing to cx_Oracle.

  • consistently use a slash (instead of a semi-colon) to terminate SQL commands (as well as PL/SQL, where of course a slash is always required)

  • write a method like RunSqlScript that reads each statement from your SQL file and executes it.

A wiser solution is to move away from SQL files and code all statements in cx_Oracle.

Sign up to request clarification or add additional context in comments.

Comments

1

After playing around with a lot of libraries I ended up using Python's sub-process to solve this issue. Posting code, as it might help someone in the future.

def connect_to_db_and_execute(timeout):
    proc = subprocess.Popen(f'sqlplus {config.DB_USERNAME}/{config.DB_PASSWORD}@{config.DB_HOST}:{config.DB_PORT}/'
                            f'{config.DB_DBASE} @C:/pathtoSql/PurgeProcess_2.sql', stdout=PIPE, stderr=PIPE, universal_newlines=True)
    timer = Timer(timeout, proc.kill)
    try:
        timer.start()
        stdout,stderr = proc.communicate()
    finally:
        timer.cancel()
    (output, err) = proc.communicate()
    print('output is ', output)
    if err:
        # iF there is an error, print and sent it via email
        print(err)
        send_email(email, pword, to_recipients, subject, err)```

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.