【IBM App Connect Enterprise】 ESQLの基本

## はじめに
IBM App Connect Enterprise（以下 ACEと略します）は、IBMが提供するシステム間連携のソフトウェアで、システム間のさまざまなギャップを整理して連携を実現します。

当記事では、ノードの設定では対応が難しい処理を実現するためのComputeノード、そこで使用するスクリプト「ESQL」について基本的な機能を理解するための情報をまとめています。
（何らかのプログラム言語を理解されている前提で記載しています）

## ESQLとは
https://www.ibm.com/docs/ja/app-connect/13.0?topic=esql-overview

**Extended Structured Query Language** の略で、オラクル社が以前から提供されている「PL/SQL」と類似したプログラミング言語です。
ですので、PL/SQLを使ったことがある方はスムーズに利用していただけるでしょう。
初見の方はクラシックなイメージを持たれるかもしれませんが、シンプルな言語なので習得には苦労しないと思います。

同じ名前で、Elasticsearchで使用するESQL（Elasticsearch Query Language）という言語もあるようですが、こちらとは関係ありません。

## Computeノードの配置と編集
Computeノードの配置は、Toolkit上でパレットからTransformationの下層にある**Compute**をドラッグし、

<img width="200" alt="qiita-square" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/38290423-0f7d-4de6-ba4b-45e256e56b0a.png">

メッセージフロー上にドロップします。
その後、Computeノードをダブルクリックするとエディタが開きます。

初期状態で次のようなスクリプトが提示されるので、これを編集していきます。
```
CREATE COMPUTE MODULE XXXXXXXX
	CREATE FUNCTION Main() RETURNS BOOLEAN
	BEGIN
		-- CALL CopyMessageHeaders();
		-- CALL CopyEntireMessage();
		RETURN TRUE;
	END;

	CREATE PROCEDURE CopyMessageHeaders() BEGIN
		DECLARE I INTEGER 1;
		DECLARE J INTEGER;
		SET J = CARDINALITY(InputRoot.*[]);
		WHILE I < J DO
			SET OutputRoot.*[I] = InputRoot.*[I];
			SET I = I + 1;
		END WHILE;
	END;

	CREATE PROCEDURE CopyEntireMessage() BEGIN
		SET OutputRoot = InputRoot;
	END;
END MODULE;
```

上記スクリプトは、プロジェクト内の**ESQLsフォルダ**に**ノード名.esql**のファイル名で作成されます。
ComputeノードとESQLファイルの関連付けは、ノードのプロパティ（Basic > ESQL module）で変更可能です。

## 基本構文

### スクリプトの構造

ESQLモジュールに関数を作成していきます。関数は
* 戻り値のある FUNCTION
* 戻り値がない PROCEDURE

の2種類に分かれます。

両方とも先頭の宣言にはCREATE...と付きます。
関数内の処理は、開始と終了を示すBEGINとENDで囲みます。

```:FUNCTIONの例
CREATE FUNCTION func1 (arg1 INTEGER, arg2 CHARACTER) RETURNS INTEGER
BEGIN
  ....
END;
```

```:PROCEDUREの例
CREATE PROCEDURE proc1 (IN arg1 INTEGER, INOUT arg2 CHARACTER)
BEGIN
  ....
END;
```
PROCEDUREは、引数に「入力のみ」「入出力兼用」「出力のみ」という指定を行ないます。戻り値はありません。

ComputeノードではMain関数が呼び出されるため、ノードに必要な処理はこの関数内に記載します。

### 主な文法
ひな形として生成されるスクリプトを見ていただければ、どのような言語かはイメージできるのではないでしょうか。
特徴は、
* 行末には「;」を付ける
* 変数宣言にはDECLAREを使う
```
DECLARE cnt INTEGER 0;
```
* 変数に代入を行なう場合にはSETを使う
```
SET cnt = cnt + 1;
```
* プロシジャの呼び出しはCALLを使う
```
CALL proc1(99, rtn);
```
* 注釈は先頭に「--」を付ける

などです。

### 変数データ型
主なデータ型は次のようなものがあります。全てのデータ型、およびデータ型の取りうる値範囲などの詳細情報はマニュアルを参照ねがいます。

https://www.ibm.com/docs/ja/app-connect/13.0?topic=reference-esql-data-types-in-message-flows

| データ種類 | データ型 | 説明 |
|:-:|:-:|:-:|
| 数値 | INTEGER  | 整数  |
|   | DECIMAL  | 小数  |
| 文字列  | CHARACTER  | 可変長文字列  |
|   | BLOB | 可変長バイナリ |
| 日時  | TIMESTAMP  | 日時  |
| その他  | ROW | ツリー構造データ |

### 比較演算子
等しい場合は =、等しくない場合は <> を使います。

### 命令
https://www.ibm.com/docs/ja/app-connect/13.0?topic=reference-esql-statements

プログラミングに必要な命令は一通り揃っています。モダンな言語のように「ライブラリを追加して言語の機能を拡張する」という仕様はありませんが、その分覚える文法は少なくて済むというメリットもあります。

#### IF文

```
IF val = 0 THEN
   ....;
ELSEIF val = 1 THEN
   ....;
ELSE
   ....;
END IF;
```
オーソドックスな書き方かと思います。最後は**END IF**で締めます。

#### WHILE文

```
WHILE I < 99 DO
    ....;
    SET I = I + 1;
END WHILE;
```
条件を満たしているあいだループを継続します。

### PROPAGATEとフロー制御
ACEで利用するノードの多くは処理後に「正常時の遷移先」「異常時の遷移先」など、状況に応じた異なる接続先を指定することができます。
接続用のコネクタをターミナルと呼びますが、「正常時の遷移先」は**Out**というターミナルから接続します。

<img width="400" alt="qiita-square" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/b36a003f-7860-4b88-80bd-1fc161ddfe29.png">

Computeノードは処理結果により2つ以上の正常時遷移先を使い分ける場合があり、このケースに備えてOut〜Out4の5つのターミナルが準備されています。
**PROPAGATE**は、このターミナルを指定することができます。

```
PROPAGATE TO TERMINAL 'out1';
```
処理中にこの命令を実行すると、Computeノード処理終了後、Out1ターミナルに接続されたノードへ進みます。

:::note warn
ターミナルの名前は先頭が大文字（Out1）ですが、コード上は先頭小文字で指定します（out1）
:::

#### PROPAGATEの利用方法
```
IF XXXX THEN
  PROPAGATE TO TERMINAL 'out1';
ELSE
  PROPAGATE TO TERMINAL 'out2';
END IF;
RETURN FALSE;
```
上記の使い方では、条件によって遷移先を切り替えています。

```
PROPAGATE TO TERMINAL 'out1';
....
PROPAGATE TO TERMINAL 'out2';
```
同じ処理のなかでPROPAGATEを複数回呼び出すこともできます。

この使い方ではOut1とOut2に接続されたノードがともに動くようになります。ただし、1回PROPAGATEの指定を行なうと出力用のメッセージがデフォルトではクリアされるため、次のPROPAGATEより前にメッセージを再度構築する必要があります。

Main関数で正常終了する場合は RETURN TRUE; で締めくくります。これは PROPAGATE TO TERMINAL 'out'; と同じ意味合いを持ちます。
そのため、PROPAGATEを使用した場合には、Main関数は基本的に RETURN FALSE; にします。

```
WHILE XXXX DO
  ....
  PROPAGATE;
END WHILE;
```
応用として、1つの入力メッセージをループで分割して複数のメッセージとして後続に流すこともできます。PROPAGATEだけを指定した場合、Outターミナルを出力先にします。

## おわりに
Computeノードではさまざまな処理をカバーすることができ、実装もそれほど難しいものではありません。
ただあまりESQLに頼ると、ローコードで連携処理を実現するACEの強みが薄くなってしまうため、ACEの機能を活用して高い生産性と品質を目指しましょう。

## さらに詳しい情報をお探しの方へ
IBMの最新情報、イベント情報、さらに役立つ資料は、以下のIBM Communityでも発信・格納されています。
最新のトレンドや有益な情報をチェックするために、ぜひご覧ください！
- **WebSphere**: [IBM Community - WebSphere](https://community.ibm.com/community/user/wasdevops/communities/community-home?CommunityKey=d6c93aa2-6e10-48da-96dc-3831da8ee185)
WebSphere関連の最新情報やディスカッション、イベント情報、技術資料を公開中！
- **ELM (Engineering Lifecycle Management)**: [IBM Community - ELM](https://community.ibm.com/community/user/sustainability/communities/community-home?CommunityKey=f8bc69e0-9d61-4688-939b-018f5f74519e)
ELMに関する最新のイベント情報、ナレッジ共有、便利なドキュメントをチェック！
- **Integration**: [IBM Community - Integration](https://community.ibm.com/community/user/integration/communities/globalgrouphome?CommunityKey=fe1b09d3-7042-4a5f-bce0-6bcc19aa0ed9)
Integrationに関する最新のイベント情報、ナレッジ共有、便利なドキュメントをチェック！