Символьная семантика в PL/SQL: локализация приложений

Символьная семантика в PL/SQL: локализация приложений

Несомненно, в числе первых проблем, с которыми вы столкнетесь при локализации своих приложений PL/SQL, будет поддержка многобайтовых символов. Когда вы передадите первый японский символ в переменную VARCHAR2 и получите ошибку ORA-6502, скорее всего, час-другой будет потрачен на отладку процедуры, которая «должна работать».

Возможно, в какой-то момент выяснится, что для поддержки многобайтовых наборов символов вам придется изменить все объявления всех символьных переменных или символьных столбцов в вашем приложении PL/SQL. Не отчаивайтесь! После решения всех начальных проблем значительно упростится управление реализацией приложения в будущем. Рассмотрим пример:

DECLARE
   v_title   VARCHAR2 (30);
BEGIN
   SELECT title
     INTO v_title
     FROM publication
    WHERE publication_id = 2;

   DBMS_OUTPUT.put_line (v_title);
EXCEPTION
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
END;

Программа выдает следующее исключение:

ORA-06502: PL/SQL: numeric or value error: character string buffer too small

Проблема в том, что точность переменной составляет 30 байтов, а не символов. Во мно­гих азиатских наборах представление одного символа занимает до 3 байтов, поэтому в переменную длины 2 не поместится ни один символ выбранного набора!

При помощи функции LENGTHB мы можем определить фактический размер строки:

DECLARE
   v_length_in_bytes   NUMBER (2);
BEGIN
   SELECT LENGTHB (title)
     INTO v_length_in_bytes
     FROM publication
    WHERE publication_id = 2;

   DBMS_OUTPUT.put_line ('String size in bytes: ' || v_length_in_bytes);
END;

Результат:

String size in bytes: 52

До выхода Oracle9i наши возможности были ограничены. Самым распространенным решением в Oracle8i было простое умножение максимального количества символов на 3:

DECLARE
   v_title   VARCHAR2 (90);
BEGIN
   SELECT title
     INTO v_title
     FROM publication
    WHERE publication_id = 2;

   DBMS_OUTPUT.put_line (v_title);
EXCEPTION
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
END;

Если в вашей системе необходимые глифы могут быть выведены на экран, возвращается следующий результат:

Oracle PL/SQLプログラミング 基礎編 第3版

Обходное решение работает, но выглядит весьма неуклюже. Байтовая семантика и умножение на 3 приводит к нежелательным последствиям для вашего приложения:

  •  Многие фирмы-разработчики СУБД по умолчанию используют символьную семантику вместо байтовой, что затруднит возможное портирование приложения.
  •  Если символы занимают не все 3 байта, в переменной или столбце может быть сохранено больше символов, чем предполагалось.
  •  Автоматическое дополнение типов данных CHAR в Oracle означает, что все 90 байт будут зарезервированы в памяти — независимо от того, используются они или нет. Символьная семантика впервые появилась в Oracle9i. При объявлении переменной размер может задаваться как в байтах, так и в символах. Следующий пример почти полностью совпадает с неудачным примером, приводившимся ранее, — с одним исключением. Взгляните на объявление переменной, чтобы понять, как активизируется символьная семантика:
DECLARE
   v_title   VARCHAR2 (30 CHAR);
BEGIN
   SELECT title
     INTO v_title
     FROM publication
    WHERE publication_id = 2;

   DBMS_OUTPUT.put_line (v_title);
EXCEPTION
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
END;

На этот раз программа выводит полную строку:

Oracle PL/SQLプログラミング 基礎編 第3版

Впрочем, и этот метод требует модификации каждой символьной переменной или объ­явления столбца в вашем приложении. Проблема проще решается переходом от байтовой семантики к символьной на уровне всей базы данных. Для этого достаточно присвоить переменной NLS_LENGTH_SEMANTICS значение CHAR. Текущее значение параметра можно узнать при помощи следующего запроса:

SELECT parameter, VALUE
  FROM nls_session_parameters
 WHERE parameter = 'NLS_LENGTH_SEMANTICS'

 Результат выполнения:

PARAMETER                 VALUE
------------------------- ----------
NLS_LENGTH_SEMANTICS      BYTE

Также информацию можно получить из представления V$PARAMETER:

SELECT NAME, VALUE
  FROM v$parameter
 WHERE NAME = 'nls_length_semantics'

Запрос возвращает следующую информацию:

NAME                      VALUE
------------------------- ----------
nls_length_semantics      BYTE

Для изменения значения NLS_LENGTH_SEMANTICS используется команда ALTER SYSTEM:

ALTER SYSTEM SET NLS_LENGTH_SEMANTICS = CHAR

Команда ALTER SESSION изменяет значение параметра на время текущего сеанса:

ALTER SESSION SET NLS_LENGTH_SEMANTICS = CHAR

При таком подходе модификация существующего приложения выполняется проще простого; все существующие объявления автоматически интерпретируются в символах вместо байтов. После перевода системы на символьную семантику изменения отражаются в словаре данных:

SELECT parameter, value
  FROM nls_session_parameters
 WHERE parameter = 'NLS_LENGTH_SEMANTICS'

Результат:

PARAMETER                 VALUE
------------------------- ----------
NLS_LENGTH_SEMANTICS      CHAR

Возвращаясь к предыдущему примеру, мы видим, что символьная семантика применяется без включения ключевого слова CHAR в объявление.

DECLARE
   v_title   VARCHAR2 (30);
BEGIN
   SELECT title
     INTO v_title
     FROM publication
     WHERE publication_id = 2;

   DBMS_OUTPUT.put_line (v_title);
EXCEPTION
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack);
END;

Результат будет таким:

Oracle PL/SQLプログラミング 基礎編 第3版

Обратите внимание: максимальный размер в байтах не изменяется при активизации символьной семантики. Хотя символьная семантика позволит разместить 1000 3-байтовых символов в переменной VARCHAR2(1000) без изменений, поместить 32,767 3-байтовых символов в переменной VARCHAR2(32767) вам не удастся.

Предельный размер переменной VARCHAR2 по-прежнему составляет 32 767 байт, а столбца VARCHAR2 — 4000 байт.

Учитывая символьную семантику при проектировании приложения, вы сильно упростите себе жизнь. Если только у вас нет веских причин для использования байтовой семантики в части вашего приложения, задайте параметр NLS_LENGTH_ SEMANTICS = CHAR, чтобы символьная семантика использовалась по умолчанию. Если вы измените настройку NLS_LENGTH_SEMANTICS для существующего приложения, не забудьте перекомпилировать все объекты, чтобы изменения вступили в силу. В частности, вам придется заново выполнить сценарий catproc.sql, чтобы повторно создать все пакеты!

 

 

Вас заинтересует / Intresting for you:

Управление приложениями PL/SQL...
Управление приложениями PL/SQL... 4651 просмотров Stas Belkov Thu, 16 Jul 2020, 06:20:48
Встроенные методы коллекций PL...
Встроенные методы коллекций PL... 14838 просмотров sepia Tue, 29 Oct 2019, 09:54:01
Основы языка PL/SQL: использов...
Основы языка PL/SQL: использов... 4700 просмотров Ирина Светлова Tue, 06 Feb 2018, 14:04:03
Программирование динамического...
Программирование динамического... 4919 просмотров Максим Николенко Sun, 09 Sep 2018, 06:56:23
Войдите чтобы комментировать