У меня возникла проблема с вставкой Unicode в схему Oracle, я думаю, что база данных является экземпляром Oracle 11g, но на данный момент я не уверен. Я использую python 2.6.1 в OS X 10.6.8 (это системная версия python) и использую модуль драйвера cx-Oracle версии 5.1, загруженный с sourceforge.net, собранный и установленный в экземпляр virtualenv 1.6.1. с видимыми пакетами сайта. Мой сценарий выглядит следующим образом

  import cx_Oracle

  connection = cx_Oracle.connect(
      "<name>/<password>@<host>/<service-name>"
      )
  cursor = connection.cursor()
  result = cursor.execute(u"create table UNICODE_TEST (id NUMBER(6), text NCLOB not NULL)")

  raw_text = open("test.txt",'r').read()
  if isinstance(raw_text,str):
      raw_text = raw_text.decode("utf_8")

  statement = u"insert into UNICODE_TEST (id, text) values (1,'%s')" % raw_text
  result = cursor.execute(statement)

Я создаю соединение, создаю курсор, выполняю статус для создания тестовой таблицы с идентификатором и текстовым полем типов NUMBER и NCLOB. Я открываю файл, содержащий текст, закодированный в UTF-8, и декодирую строку в Unicode. Создайте статус вставки в строке Unicode и выполните этот оператор, и результатом будет эта ошибка.

  Traceback (most recent call last):
    File "unicode-test.py", line 19, in <module>
      result = cursor.execute(statement)
  UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 170: ordinal not in range(128)

Что-то пытается закодировать мой оператор как ASCII перед тем, как вставить его в схему Oracle. Поэтому я начал поиски, чтобы лучше понять, как cx-Oracle обрабатывает Unicode, и нашел это в HISTORY.txt исходного кода cx-Oracle, который я загрузил с sourceforge.net.

Изменения с 5.0.4 на 5.1
1) Убрать поддержку режима UNICODE и разрешить передачу Unicode в везде, где может быть передана строка. Это означает, что строки будут передается в Oracle с использованием значения среды NLS_LANG также переменная в Python 3.x. Это устранило кучу проблем. которые были обнаружены при использовании режима UNICODE, а также удалены ненужные ограничение в Python 2.x, что Unicode нельзя использовать в строках подключения или операторы SQL, например. ...

Я предполагаю, что для переменной среды NLS_LANG установлено значение ascii или какой-либо эквивалент, поэтому я пытаюсь установить для NLS_LANG значение AL32UTF8, которое, как я считаю, является правильным значением для Unicode, и устанавливаю новое значение перед созданием моего соединения.

  os.environ["NLS_LANG"] = "AL32UTF8"
  connection = cx_Oracle.connect(
      "<user>/<password>@<host>/<service-name>"
      )
  cursor = connection.cursor()
  ...

Но я получаю эту ошибку.

  Traceback (most recent call last):
    File "unicode-test.py", line 11, in <module>
      "<user>/<password>@<host>/<service-name>"
  cx_Oracle.DatabaseError: ORA-12705: Cannot access NLS data files or invalid environment specified

Похоже, я не могу изменить значение NLS_LANG.

Вот мои вопросы на данный момент. Мне не хватает чего-то простого, например, неправильного типа столбца? Проблема с драйвером cx-Oracle? Нужно ли мне устанавливать переменную среды WITH_UNICODE при сборке модуля cx-Oracle, и как мне это сделать? Проблема с экземпляром Oracle? У меня мало опыта работы с Oracle, и я никогда не работал с Oracle и python вместе. Я потратил два дня на работу над этой проблемой и хотел бы лучше понять, в чем проблема, прежде чем я пойду в группу администраторов баз данных.

Благодарность,

18
snarkyname77 9 Янв 2013 в 19:35

1 ответ

Лучший ответ

Установка переменной окружения - правильный путь, но "AL32UTF8" - неправильное значение для NLS_LANG. Чтобы получить правильное значение NLS_LANG, используемого в вашем экземпляре Oracle, выполните

SELECT USERENV ('language') FROM DUAL  
15
DecimusXIV 4 Апр 2013 в 09:49
Спасибо за ответ, наконец-то я получил ответ от своих администраторов баз данных. Для нашей установки 11gR2 НАБОР СИМВОЛОВ - «WE8MSWIN1252», а НАБОР НАЦИОНАЛЬНЫХ СИМВОЛОВ - «AL16UTF16». Похоже, что драйвер неправильно определяет кодировку, установленную в указанных выше переменных. Проверка атрибутов encoding и nencoding в соединении дает US-ASCII в обоих случаях, что неверно. Я все еще получаю ту же ошибку DatabaseError при попытке NLS_LANG на «AL16UTF16», что, поскольку мое подключение к схеме было удалено (и также будет в производстве), объясняет, почему эти файлы недоступны.
 – 
snarkyname77
18 Апр 2013 в 17:39
В моей ситуации результатом запроса выше является «AMERICAN_AMERICA.US7ASCII». Однако мои вставки Unicode начали работать правильно, как только мой NLS_LANG был установлен на "_.AL32UTF8" (без кавычек).
 – 
davidjb
8 Май 2013 в 05:22
Мой результат из приведенного выше запроса: AMERICAN_AMERICA.WE8MSWIN1252. @davidjb, как установить это значение без кавычек. Что вы импортировали в свой прицел, чтобы получить его?
 – 
ThatAintWorking
21 Июн 2014 в 02:06
6
Я нашел эту страницу, код которой был os.environ["NLS_LANG"] = ".AL32UTF8" и это помогло мне. Обратите внимание на начальную точку, но без подчеркивания.
 – 
ThatAintWorking
21 Июн 2014 в 02:09