Регистрация по ссылке.
Рубрика: Основы ABAP
Введение в основные понятия необходимые для понимания процессов разработки на языке ABAP
Запуск транзакций из сообщений
В подробных текстах сообщений (тр. SE91) или в документации (тр. SO10) мы кроме непосредственно описания можем так же вставлять ссылки на транзакции или отчёты для их запуска, что позволяет упростить жизнь пользователям.
Однако у стандартной реализации данного механизма есть ряд ограничений:
- Длинна ссылки ограничена, из-за чего передать все необходимые параметры для запуска транзакции может не получиться.
- Нет возможности вставки интернет-ссылок более 70 символов (ограничение стандарта).
- Нет возможности запуска отчёта с параметрами (только запуск с вариантом).
В статье рассмотрим каким образом можно расширить стандартные возможности чтобы избежать вышеуказанных ограничений.
Запуск транзакций из SBWP
Иногда нам необходимо оповестить пользователя о каком-либо событии по внутренней почте, с возможностью его перехода к заданной транзакции и с учётом контекста оповещения, т.е. с заполнением параметров актуальных для данного оповещения.
Во внутренней почте мы можем сформировать ссылку на бизнес объект (транзакция SWO1), а уже у бизнес объекта реализовать метод display для запуска нужной нам транзакции.
Давайте разберёмся как это сделать.
Внутренние таблицы как источник в SQL запросах
В релизе ABAP 7.52 стало возможным использование внутренних таблиц как источника данных в ABAP SQL:
1 |
SELECT FROM ...@itab AS table_alias... |
Существует два сценария выполнения таких запросов:
- Для выполнения SQL запроса не требуется переноса содержимого внутренней таблицы на уровень СУБД. В таком случае обработка запроса осуществляется непосредственно на сервере приложений, по аналогии с табличным буфером.
- Для выполнения SQL запроса требуется перенести содержимое внутренней таблицы во временную таблицу на уровень СУБД. Этот сценарий поддерживается не всеми СУБД и чтобы статический анализ кода не ругался, следует использовать прагму: ##itab_db_select. При отсутствии поддержки система выдаст исключение в runtime — CX_SY_SQL_UNSUPPORTED_FEATURE.
Разберём текущие особенности использования этих сценариев.
Динамические журнальные точки
В ABAP довольно таки давно существует функционал журнальных точек, который позволяет активировать запись в журнал (в тр. SAAB) определённых данных из программы. Для этого необходимо завести ключ (ID группы контрольных точек) и в коде использовать оператор LOG-POINT.
Но что если необходимо поместить в журнал некоторые данные при выполнении программы, а менять код нельзя? Или необходимо понять откуда конкретно вызывается анализируемый код?
Для этих целей начиная с ABAP 7.5 ввели так называемые динамические журнальные точки, которые позволяют:
- Сохранять значения переменных по определённым условиям
- Записывать стек вызовов, чтобы понять откуда происходит вызов того или иного кода
- Выполнять анализ выполнения отдельного SQL выражения
- Активировать запись SQL трассировки для заданного выражения оп указанному условию
- Активировать трассировку использования табличного буфера заданного SQL выражения для анализа потребляемой памяти
Создавать или модифицировать журнальные точки можно либо через ADT (Eclipse), либо через транзакцию SDLP.
Далее на простых примерах рассмотрим вариант использования.
AMDP Функции
Начиная с релиза ABAP 7.50 у нас появилась возможность создания не только AMDP процедур, но и AMDP функций. В зависимости от типа AMDP функции они могут быть вызваны:
- непосредственно из ABAP кода,
- из других AMDP методов,
- как источник данных для специальной ABAP CDS сущности называемой табличной функцией CDS.
Далее рассмотрим все варианты использования AMDP функций.
Короткая форма VALUE при формировании таблиц
У оператора VALUE #( ) при формировании внутренних таблиц есть так называемая короткая форма:
1 2 3 4 5 6 7 8 |
VALUE dtype|#( [let_exp] [BASE itab] col1 = dobj11 ... ( col2 = dobj12 col3 = dobj13 ... ) ( col2 = dobj22 col3 = dobj23 ... ) ... col1 = dobj31 col2 = dobj32 ... ( col3 = dobj33 ... ) ( col3 = dobj43 ... ) ... ). |
Что соответствует следующему полному синтаксису:
1 2 3 4 5 6 7 8 |
VALUE dtype|#( [let_exp] [BASE itab] ( col1 = dobj11 ... col2 = dobj12 col3 = dobj13 ... ) ( col1 = dobj11 ... col2 = dobj22 col3 = dobj23 ... ) ... ( col1 = dobj31 col2 = dobj32 ... col3 = dobj33 ... ) ( col1 = dobj31 col2 = dobj32 ... col3 = dobj43 ... ) ... ). |
Таким образом мы можем не указывать все столбцы, если хотим их заполнить на основе столбцов вне внутренних скобок.
Удобно использовать для формирования диапазонов:
1 2 3 4 5 6 |
DATA lt_range TYPE RANGE OF i. lt_range = VALUE #( sign = 'I' option = 'BT' ( low = 1 high = 10 ) ( low = 21 high = 30 ) ( low = 41 high = 50 ) option = 'GE' ( low = 61 ) ). |
Все что указано за пределами внутренних скобок дублируется в следующие строки:
SIGN | OPTION | LOW | HIGH |
I | BT | 1 | 10 |
I | BT | 21 | 30 |
I | BT | 41 | 50 |
I | GE | 61 | 0 |
Но данный синтаксис в случае вложенных конструкторных операторов может приводить к непредвиденным результатам.
1 2 3 4 5 |
DATA lt_range TYPE RANGE OF i. lt_range = VALUE #( ( low = 1 ) ( VALUE #( sign = 'I' option = 'EQ' low = 2 ) ) ( low = 3 ) ). |
Исходя из документации в третьей строке мы должны увидеть пустые значения sign и option, т.к. мы ничего не указывали за пределами внутренних скобок, однако они заполнены из второй строки:
SIGN | OPTION | LOW | HIGH |
1 | 0 | ||
I | EQ | 2 | 0 |
I | EQ | 3 | 0 |
Описанное поведение судя по всему является багом, исправление будет под нотой: 3042453
SELECT SINGLE и UP TO 1 ROWS
Казалось бы, выборка единственной записи из таблицы довольно простая и логически понятная операция, однако все еще частой ошибкой находимой на code-review является следующее предупреждение Code Inspector’a:
Syntax check warning
In «SELECT SINGLE …», the WHERE condition for a key field does not test for equality or the FROM clause contains a join. This means the result is possibly not unique. Internal message code: MESSAGE GSB
Deactivatable using pragma ##WARN_OK. Message Code WRN 1305
Далее рассмотрим что это такое и почему это не нужно игнорировать.
Просмотр каталога полей любого ALV
Иногда бывает полезно посмотреть каталог ALV без погружения в код или в отладку. Cделать это можно для любого ALV зажав Shift и щёлкнув два раза правой кнопкой мыши на не занятом данными месте, пример:
Откроется сервисный инструмент (alv consistency check), где среди прочего есть каталог полей:
В полноэкранных ALV можно просто набрать команду &SOS.
Табличные выражения и исключения
Начиная с версии ABAP 7.40 мы можем считывать данные из таблиц через табличные выражения следующим образом:
1 2 3 4 5 |
TRY. ls_row = lt_itab[ id = lv_find_id ]. CATCH cx_sy_itab_line_not_found. " INTO DATA(lo_exception) " В случае отсутствия записи необходимо обработать исключение. ENDTRY. |
Однако такой вариант кроме того что является слишком длинным аналогом других, может оказывать существенное влияние на производительность в случае частого отсутствия записей, т.к. старт исключения довольно затратная операция. Альтернативные варианты могут быть следующими:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
" Все эти варианты не требуют обработки исключений в блоке TRY..CATCH ls_row = VALUE #( lt_itab[ id = lv_find_id ] OPTIONAL ). " IF ls_row IS NOT INITIAL... ls_row = VALUE #( lt_itab[ id = lv_find_id ] DEFAULT ls_default ). DATA(lr_row) = REF #( lt_itab[ id = lv_find_id ] OPTIONAL ). " IF lr_row IS BOUND... ASSIGN lt_itab[ id = lv_find_id ] TO FIELD-SYMBOL(<ls_row>). " IF sy-subrc = 0... READ TABLE lt_itab INTO row WITH KEY id = lv_find_id. " IF sy-subrc = 0... " Если нужно проверить только наличие записи DATA(lv_idx) = line_index( lt_itab[ id = lv_find_id ] ). READ TABLE lt_itab WITH KEY id = lv_find_id TRANSPORTING NO FIELDS. " IF sy-subrc = 0... |
Сравнение на примере: