Вставка данных юникода в базу данных 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 автоматически по доктрине).
У кого-нибудь есть какие-нибудь идеи относительно того, где я ошибаюсь?
2 answers
Ваша проблема не связана с PHP: ваш столбец "MY_CURRENCY"."SYMBOL"
, вероятно, определяется как VARCHAR2(4 byte)
вместо VARCHAR2(4 CHAR)
.
Поскольку символ юникода может занимать более одного байта, вам необходимо использовать CHAR
при определении переменных таблиц и . Вот почему вы получаете сообщение об ошибке Oracle.
Вы должны иметь возможность изменять свою таблицу:
ALTER TABLE MY_CURRENCY MODIFY (SYMBOL VARCHAR2(4 CHAR));
, А затем вставьте любые 4 символа в этот столбец.
Во-первых, какую версию 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, чтобы иметь возможность изменять параметры инициализации), все сценарии, созданные вашей платформой, будут использовать семантика символов по умолчанию.