cx_Oracle «ORA-01843: недопустимый месяц» с параметром Unicode

У меня есть следующее: (используя ipython)

In [30]: con = cx_Oracle.connect('refill_test02/******@MYDB')

In [31]: cur = con.cursor()

In [32]: cur.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")

In [33]: cur.execute("select to_date(:0), to_timestamp(:1) from dual", ['2013-03-12', '2013-03-12 08:22:31.332144'])
Out[33]: <__builtin__.OracleCursor on <cx_Oracle.Connection to refill_test02@MYDB>>

In [34]: cur.fetchall()
Out[34]: 
[(datetime.datetime(2013, 3, 12, 0, 0),
  datetime.datetime(2013, 3, 12, 8, 22, 31, 332144))]

In [35]: cur.execute("select to_date(:0), to_timestamp(:1) from dual", [u'2013-03-12', '2013-03-12 08:22:31.332144'])
Out[35]: <__builtin__.OracleCursor on <cx_Oracle.Connection to refill_test02@MYDB>>

In [36]: cur.fetchall()
Out[36]: 
[(datetime.datetime(2013, 3, 12, 0, 0),
  datetime.datetime(2013, 3, 12, 8, 22, 31, 332144))]

In [37]: cur.execute("select to_date(:0), to_timestamp(:1) from dual", [u'2013-03-12', u'2013-03-12 08:22:31.332144'])
---------------------------------------------------------------------------
DatabaseError                             Traceback (most recent call last)
/home/xxxxx/<ipython-input-37-8af80e5fc40c> in <module>()
----> 1 cur.execute("select to_date(:0), to_timestamp(:1) from dual", [u'2013-03-12', u'2013-03-12 08:22:31.332144'])

DatabaseError: ORA-01843: not a valid month


In [38]: cur.execute("select to_date(:0), to_timestamp(:1) from dual", [u'2013-03-12', '2013-03-12 08:22:31.332144'])
---------------------------------------------------------------------------
DatabaseError                             Traceback (most recent call last)
/home/xxxx/<ipython-input-38-bc628f006aa3> in <module>()
----> 1 cur.execute("select to_date(:0), to_timestamp(:1) from dual", [u'2013-03-12', '2013-03-12 08:22:31.332144'])

DatabaseError: ORA-01843: not a valid month


In [39]: cur.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")

In [40]: cur.execute("select to_date(:0), to_timestamp(:1) from dual", [u'2013-03-12', '2013-03-12 08:22:31.332144'])
Out[40]: <__builtin__.OracleCursor on <cx_Oracle.Connection to refill_test02@MYDB>>

In [41]: cur.fetchall()
Out[41]: 
[(datetime.datetime(2013, 3, 12, 0, 0),
  datetime.datetime(2013, 3, 12, 8, 22, 31, 332144))]

По какой-то причине я не могу использовать строку юникода для параметра временной метки (IN[37]), что еще более странно, так это то, что после того, как я это сделаю, мне нужно сбросить форматы NLS сеанса, прежде чем он снова заработает с нормальной строкой.

Я использую: Cx_Oracle 5.1.2 Python 2.7.3 Oracle 10.2.0.1.0

Любые идеи?

Спасибо за ваше время на чтение этого.


person Magarato    schedule 13.03.2013    source источник


Ответы (3)


На самом деле это ошибка в Oracle 10.5.0.2 и 11.2.0.1.

Баг можно воспроизвести следующим образом:

установите NLS_TIMESTAMP_FORMAT в сеансе.

Запустите любое неявное или явное преобразование TO_DATE с данными Unicode.

Следующий неявный или явный TO_TIMESTAMP с данными Unicode вызовет внутренний сброс формата временной метки.

Все последовательные TO_TIMESTAMP завершатся ошибкой, а TO_CHAR временной метки приведет к недопустимому выводу.

Вот код для проверки поведения:

ALTER SESSION SET NLS_TERRITORY = 'AMERICA';
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF';

REM --- WORKS:
SELECT TO_TIMESTAMP('2013-06-24 18:15:10.312') FROM DUAL;

REM --- WORKS:
SELECT TO_DATE('2013-06-24 18:15:10') FROM DUAL;

REM --- WORKS:
SELECT TO_TIMESTAMP('2013-06-24 18:15:10.312') FROM DUAL;

REM --- WORKS:
SELECT TO_TIMESTAMP(x) FROM (SELECT CAST('2013-06-24 18:15:10.312' AS NVARCHAR2(30)) AS X FROM DUAL);

REM --- WORKS:
SELECT TO_DATE(x) FROM (SELECT CAST('2013-06-24 18:15:10' AS NVARCHAR2(30)) AS X FROM DUAL);

REM --- WORKS:
SELECT TO_TIMESTAMP('2013-06-24 18:15:10.312') FROM DUAL;

REM !!! FAILS!
SELECT TO_TIMESTAMP(x) FROM (SELECT CAST('2013-06-24 18:15:10.312' AS NVARCHAR2(30)) AS X FROM DUAL);

REM !!! FAILS!
SELECT TO_TIMESTAMP('2013-06-24 18:15:10.312') FROM DUAL;

REM --- WORKS:
SELECT TO_DATE('2013-06-24 18:15:10') FROM DUAL;
person jtiai    schedule 24.06.2013

На основе jtiai описания, я сделал следующий обходной путь - перед вызовом любого проблемного sql-s (например, oracle 10.5.0.2 и 11.2.0.1, cx_oracle 5.1.2) снова сбросьте NLS_DATE_FORMAT/NLS_TIMESTAMP_FORMAT:

cursor.execute(
     "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
     " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")

# do execute ...
cursor.execute(query, params)
person Robert Lujo    schedule 31.10.2013

Мне не удалось воссоздать ошибку с помощью RHEL 5, Cx_Oracle 5.1, python 2.4.3, Oracle 11.2.0.3.0. Вы пытались использовать строки формата с функциями to_date и to_timestamp?

https://gist.github.com/fclrc/5435561

#! /bin/python
import cx_Oracle
import platform

print ("Python version: " + platform.python_version())
print ("cx_Oracle version: " + cx_Oracle.version)
print ("Oracle client: " + str(cx_Oracle.clientversion()).replace(', ','.'))

connection = cx_Oracle.connect('user/pass@tns')
cursor = connection.cursor()
#
# Option with format strings
#
cursor.execute("""select to_date(:arg1,'yyyy-mm-dd'), to_timestamp(:arg2,'yyyy-mm-dd hh24.mi.ss.ff') from dual""", arg1=u'2013-03-12', arg2=u'2013-03-12 08:22:31.332144')
#
# Option without format strings
#
#cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")
#cursor.execute("select to_date(:0), to_timestamp(:1) from dual", [u'2013-03-12', u'2013-03-12 08:22:31.332144'])

mydate = cursor.fetchall()
print mydate
cursor.close()
connection.close()
person pygator    schedule 22.04.2013
comment
Он отлично работает с использованием строк формата, проблема в том, что код SQL генерируется Django при сохранении модели, и я хотел избежать вставки вручную. Спасибо за ответ. - person Magarato; 01.05.2013