Вставка данных юникода в базу данных Oracle с помощью Doctrine2 и Symfony2


Я пишу приложение с использованием Symfony2 и Doctrine2, где мне нужно использовать Oracle в качестве своей базы данных (с которой я не знаком, я почти всегда использую MySQL). Я установил Oracle XE на свой ящик разработчика и создал пользователя.

Мои параметры подключения выглядят так в моей конфигурации Symfony2:

database_driver: oci8
database_host: localhost
database_name: xe
database_user: myusername
database_password: mypassword
database_port: 1521
database_charset: AL32UTF8

При запуске php app/console doctrine:schema:create в командной строке схема создается успешно, но при попытке загрузить мои начальные приспособления с помощью php app/console doctrine:fixtures:load я получаю следующее ошибка:

[Doctrine\DBAL\DBALException]
An exception occurred while executing 'INSERT INTO my_currency 
(id, code, name, symbol) VALUES (?, ?, ?, ?)' with params 
{"1":3,"2":"RUB","3":"Russian Ruble","4":"\u0440\u0443\u0431."}:

ORA-12899: value too large for column "MYUSERNAME"."MY_CURRENCY"."SYMBOL" 
(actual: 7, maximum: 4)

В моем скрипте fixtures есть следующие данные для вставки этой строки:

array('RUB', 'Russian Ruble', 'руб.'),

Сущность определяется как:

Foo\MyBundle\Entity\Currency:
  type: entity
  table: my_currency
  id:
    id:
      type: integer
      generator: { strategy: AUTO }
  fields:
    code:
      type: string
      length: 3
    name:
      type: string
      length: 64
    symbol:
      type: string
      length: 4

Насколько я понимаю, Oracle XE имеет набор символов по умолчанию UTF-8, поэтому типам полей не нужно устанавливать значение NVARCHAR2 (они устанавливаются в VARCHAR2 автоматически по доктрине).

У кого-нибудь есть какие-нибудь идеи относительно того, где я ошибаюсь?

Author: Kris, 2012-11-13

2 answers

Ваша проблема не связана с PHP: ваш столбец "MY_CURRENCY"."SYMBOL", вероятно, определяется как VARCHAR2(4 byte) вместо VARCHAR2(4 CHAR).

Поскольку символ юникода может занимать более одного байта, вам необходимо использовать CHAR при определении переменных таблиц и . Вот почему вы получаете сообщение об ошибке Oracle.

Вы должны иметь возможность изменять свою таблицу:

ALTER TABLE MY_CURRENCY MODIFY (SYMBOL VARCHAR2(4 CHAR));

, А затем вставьте любые 4 символа в этот столбец.

 3
Author: Vincent Malgrat, 2012-11-13 11:18:50

Во-первых, какую версию Oracle XE вы используете и какой набор символов вы используете? Если вы используете версию Oracle XE 10g, была возможность загрузить версию, в которой использовался западноевропейский набор символов в дополнение к версии, в которой использовался набор символов Юникода. Что возвращают эти запросы?

SELECT *
  FROM v$version

SELECT *
  FROM v$nls_parameters
 WHERE parameter LIKE '%CHARACTERSET';

Предполагая, что база данных использует набор символов Юникода, по умолчанию Oracle определяет длину столбца VARCHAR2 (или столбца NVARCHAR2) в терминах байты, а не символы. Если у вас есть данные, которые находятся за пределами набора символов US7ASCII, набор символов AL32UTF8 требует более 1 байта памяти. Похоже, что данные, которые вы пытаетесь вставить в столбец SYMBOL, требуют 7 байт памяти, хотя они могут содержать всего 4 символа.

Существует два общих подхода к решению этой проблемы. Первый - утроить размер выделяемых столбцов (обычно один символ в наборе символов AL32UTF8 требуется не более трех байтов, хотя в некоторых исключительных случаях требуется четыре байта). Вместо того, чтобы указывать длину 4 байта, вы бы указали длину 12 байт (CODE станет 9 байтами, а NAME станет 192 байтами). Второе - изменить NLS_LENGTH_SEMANTICS так, чтобы столбец VARCHAR2 выделял размер в символах, а не в байтах

ALTER SYSTEM SET nls_length_semantics = CHAR scope= BOTH

Как только вы это сделаете (вам нужно будет войти в систему как SYS, чтобы иметь возможность изменять параметры инициализации), все сценарии, созданные вашей платформой, будут использовать семантика символов по умолчанию.

 2
Author: Justin Cave, 2012-11-13 11:22:16