Autonomous Database：Azure Functionsの関数をSQLファンクションとしてコールしてみた



# 1. Azure Functionsの関数の作成

今回は、こちらの手順に従ってmyAzureFunction777という名前の関数を作成しました。

https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-create-function-app-portal

# 2. Azureサービス・プリンシパルの有効化
DBMS_CLOUD_ADMIN.ENABLE_PRINCIPAL_AUTHプロシージャを使用して、Azureサービス・プリンシパルを有効化します。
パラメータparamsのazure_tenantidにはAzureのテナントIDを指定します。
```
SQL> BEGIN
  2      DBMS_CLOUD_ADMIN.ENABLE_PRINCIPAL_AUTH(
  3          provider => 'AZURE',
  4          username => 'admin',
  5          params   => JSON_OBJECT('azure_tenantid' value 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'));
  6  END;
  7* /

PL/SQLプロシージャが正常に完了しました。

SQL> 
```
CLOUD_INTEGRATIONSビューからAzureサービス・プリンシパルの設定に必要な情報を取得します。
```
SQL> SELECT param_name, param_value FROM CLOUD_INTEGRATIONS
  2* WHERE param_name LIKE 'azure%';

PARAM_NAME           PARAM_VALUE                                                                                                                                                                       
____________________ _________________________________________________________________________________________________________________________________________________________________________________ 
azure_app_name       ADBS_APP_OCID1.AUTONOMOUSDATABASE.OC1.AP-TOKYO-1.AXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                                                                     
azure_consent_url    https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/v2.0/authorize?client_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&response_type=code&scope=User.read    
azure_tenantid       xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx                                                                                                                                              

SQL>
```
上記のSQLで取得したazure_consent_urlのURLにアクセスし、「承諾」をクリックします。
![スクリーンショット 2023-12-21 11.22.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/80011d7c-17b0-c53e-16f4-b59b7f2c65ed.png)

Autonomous Databaseがエンタープライズアプリケーションに登録されます。
![スクリーンショット 2023-12-21 12.03.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/319dd4c2-ac4f-5148-fd07-4bebac1acde6.png)

Azure Functionsのアクセス制御にアクセスし、「ロールの割り当ての追加」をクリックします。
![スクリーンショット 2023-12-21 12.06.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/3719dff2-5de7-4316-3d96-fb82a8fc2b9a.png)
適切なロールを選択し、メンバーとしてエンタープライズアプリケーションに追加されたAutonomous Databaseを追加し、ロールの割り当てを完了します。
![スクリーンショット 2023-12-21 12.08.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/cb537499-42f0-7f8e-bd24-77fae13a2887.png)

# 3. Azure Functionsの関数をSQLファンクションとして登録

ファンクション・カタログAZURE_DEMO_CATALOGを作成します。
```
SQL> BEGIN
  2      DBMS_CLOUD_FUNCTION.CREATE_CATALOG (
  3          credential_name  => 'AZURE$PA', 
  4          catalog_name     => 'AZURE_DEMO_CATALOG', 
  5          service_provider => 'AZURE',
  6          cloud_params     => '{"subscription_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}'
  7   );
  8  END;
  9* /

PL/SQLプロシージャが正常に完了しました。

SQL>
```
ファンクション・カタログAZURE_DEMO_CATALOG内の関数をリストします。
```
SQL> VAR function_list CLOB;
SQL> 
SQL> BEGIN
  2   DBMS_CLOUD_FUNCTION.LIST_FUNCTIONS (
  3      credential_name  => 'AZURE$PA',
  4      catalog_name     => 'AZURE_DEMO_CATALOG',
  5      function_list     => :function_list
  6  );
  7  END;
  8* /

PL/SQLプロシージャが正常に完了しました。

SQL> 
SQL> SELECT JSON_QUERY (:function_list, '$' RETURNING VARCHAR2(32676) pretty) AS search_results FROM dual;

SEARCH_RESULTS                                                                                                                                                                                                                                                                                                                         
______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ 
[
  {
    "functionName" : "MyAzureFunction777",
    "functionArn" : "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/Default/providers/Microsoft.Web/sites/myAzureFunction777/functions/MyAzureFunction777",
    "invokeEndpoint" : "https://myazurefunction777.azurewebsites.net/api/myazurefunction777"
  }
]    

SQL> 
```

DBMS_CLOUD_FUNCTION.SYNC_FUNCTIONSを使用して、カタログ内の関数のラッパーSQLファンクションを作成します。
```
SQL> BEGIN
  2   DBMS_CLOUD_FUNCTION.SYNC_FUNCTIONS (
  3          catalog_name => 'AZURE_DEMO_CATALOG'
  4   );
  5  END;
  6* /

PL/SQLプロシージャが正常に完了しました。

SQL>
```
ラッパーSQLファンクションが作成されたか確認してみます。
```
SQL> SELECT object_name FROM user_objects WHERE object_type='FUNCTION';

OBJECT_NAME           
_____________________ 
MYAZUREFUNCTION777    

SQL> 
```
Azure Functionsの関数myAzureFunction777のラッパーSQLファンクションMYAZUREFUNCTION777が作成されていることが確認できました。

describeコマンドでファンクションMYAZUREFUNCTION777の引数を確認してみます。
```
SQL> desc MYAZUREFUNCTION777

FUNCTION MYAZUREFUNCTION777 RETURNS CLOB

引数名       タイプ     In/Out    デフォルトかどうか    
_________ _______ _________ ____________ 
PARAMS    CLOB    IN        unknown      
SQL> 
```

# 4. Azure Functionsの関数のラッパーSQLファンクションの実行

ラッパーSQLファンクションMYAZUREFUNCTION777を引数なしで実行してみます。
```
SQL> set long 2000
SQL> SELECT MYAZUREFUNCTION777(PARAMS=>'') response FROM dual;

RESPONSE                                                                                                                                                                      
_____________________________________________________________________________________________________________________________________________________________________________ 
{"STATUS":"200","RESPONSE_BODY":"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."}    

SQL>
```
Azure Functionsの関数myAzureFunction777が実行され、レスポンスが正しく返ってきている事が確認できました。

ラッパーSQLファンクションMYAZUREFUNCTION777を引数に{"name":"500InternalServerError"}を指定して実行してみます。
```
SQL> SELECT MYAZUREFUNCTION777(PARAMS=>'{"name":"500InternalServerError"}') response FROM dual;

RESPONSE                                                                                                                 
________________________________________________________________________________________________________________________ 
{"STATUS":"200","RESPONSE_BODY":"Hello, 500InternalServerError. This HTTP triggered function executed successfully."}    

SQL>
```
Azure Functionsの関数myAzureFunction777が実行され、引数ありの場合のレスポンスが正しく返ってきている事が確認できました。

関数のモニター画面で呼び出しの状況を確認します。
![スクリーンショット 2023-12-21 13.29.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/85e25c9a-3df8-7d80-1c1f-c01f1d841fd5.png)

Autonmous Databaseからの関数の呼び出しが成功となっていることが確認できました。

以上で、Autonomous DatabaseからAzure Functionsの関数をSQLファンクションとしてコールできることが確認できました。

# 参考情報
・[Steps to Invoke Azure Function as SQL Functions](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/user-defined-functions-autonomous.html#GUID-444A71E2-C0AE-4564-86CD-CCE619DCA383)
・[Use Azure Service Principal with DBMS_CLOUD](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/azure-service-principal.html#GUID-C01C3AC1-E03A-434E-8D0F-73F3B8830B06)
・[Azure Portal で初めての関数を作成する](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-create-function-app-portal)