# 通知設計書 116-@dsql null

## 概要

本ドキュメントは、sp_BlitzIndexストアドプロシージャにおいて、動的SQL変数@dsqlがNULLになった場合にエラーを発生させるメッセージの設計を定義します。

### 本通知の処理概要

sp_BlitzIndex実行時に、インデックス情報を取得するための動的SQL文字列（@dsql変数）がNULLになった場合に、処理を中断してエラーメッセージを出力します。

**業務上の目的・背景**：sp_BlitzIndexは動的SQLを使用して各種インデックス情報を取得します。@dsql変数は、対象データベースやオブジェクトに応じた動的クエリ文字列を格納しますが、文字列連結の過程でNULLが含まれると結果がNULLになり、クエリが実行不能になります。この通知は、そのような内部エラー状態を検出し、開発者やDBAに問題箇所を特定させるためのデバッグ支援機能です。

**通知の送信タイミング**：sp_BlitzIndex内の複数箇所で、動的SQL文字列を構築した直後、sp_executesql実行前に@dsql IS NULLのチェックが行われ、NULLの場合に送信されます。これは各種インデックス情報取得処理（#IndexSanity、#IndexColumns、#IndexPartitionSanity等への挿入）の前に発生します。

**通知の受信者**：sp_BlitzIndexを実行しているデータベース管理者がSSMS（SQL Server Management Studio）のメッセージタブで受信します。重大度16のため、処理が中断されます。

**通知内容の概要**：「@dsql is null」というメッセージで、動的SQL変数がNULLであることを伝えます。

**期待されるアクション**：このエラーが発生した場合、sp_BlitzIndexの入力パラメータやターゲットデータベースの状態を確認する必要があります。また、sp_BlitzIndexのバグの可能性もあるため、最新バージョンへの更新やGitHubでのイシュー報告を検討してください。

## 通知種別

コンソール出力（RAISERROR）- エラーメッセージ（処理中断）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（RAISERROR） |
| 優先度 | 高（エラー：処理中断） |
| リトライ | なし（エラー終了） |

### 送信先決定ロジック

sp_BlitzIndexを実行しているクライアントセッションに対して、RAISERRORによるエラーメッセージ出力として送信されます。重大度16のため、TRY-CATCHで捕捉されない限り処理が中断されます。

## 通知テンプレート

### コンソール出力の場合

| 項目 | 内容 |
|-----|------|
| メッセージ形式 | RAISERROR |
| 重大度 | 16（エラー） |
| 状態 | 1 |

### 本文テンプレート

```
@dsql is null
```

### 添付ファイル

なし

## テンプレート変数

なし（固定メッセージ）

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ストアドプロシージャ実行 | 動的SQL構築後 | @dsql IS NULL | 動的SQL変数がNULLの場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| @dsql IS NOT NULL | 正常に動的SQLが構築された場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[sp_BlitzIndex実行] --> B[動的SQL構築]
    B --> C{@dsql IS NULL?}
    C -->|No| D[sp_executesql実行]
    C -->|Yes| E[RAISERROR @dsql is null]
    E --> F[処理中断]
    D --> G[次の処理へ]
```

## データベース参照・更新仕様

### 参照テーブル一覧

このエラーは動的SQL構築段階で発生するため、特定のテーブル参照前に発生します。

### 更新テーブル一覧

該当なし（エラー発生時は更新処理前に中断）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| @dsql NULL | 動的SQL文字列構築でNULL値が含まれた | パラメータ確認、sp_BlitzIndex更新 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（エラー終了） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

なし

### 配信時間帯

制限なし

## セキュリティ考慮事項

- エラーメッセージには機密情報は含まれていません
- 内部処理の状態を示すデバッグ用メッセージです

## 備考

- このエラーは以下の処理で発生する可能性があります：
  - #IndexColumnsへのクラスタ化インデックス/ヒープデータ挿入
  - #IndexColumnsへの非クラスタ化インデックスデータ挿入
  - #IndexSanityへのインデックス情報挿入
  - #IndexPartitionSanityへのパーティション情報挿入
  - #ForeignKeysへの外部キー情報挿入
  - #UnindexedForeignKeysへの未インデックス外部キー情報挿入
  - #Statisticsへの統計情報挿入
  - #ComputedColumnsへの計算列情報挿入
  - #TemporalTablesへのテンポラル表情報挿入
- sp_BlitzIndex.sqlの複数箇所（13箇所以上）で同じパターンのチェックが実装されています

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

@dsql変数の宣言と使用パターンを理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sp_BlitzIndex.sql | `sp_BlitzIndex.sql` | @dsql変数の宣言（NVARCHAR(MAX)） |

**読解のコツ**: DECLARE @dsql NVARCHAR(MAX)を検索し、変数の定義を確認します。

#### Step 2: エントリーポイントを理解する

@dsql IS NULLチェックの発生箇所を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sp_BlitzIndex.sql | `sp_BlitzIndex.sql` | IF @dsql IS NULL RAISERRORパターン |

**主要処理フロー**:
1. **行1307-1308**: #IndexColumnsへのクラスタ化インデックスデータ挿入前
2. **行1377-1378**: #IndexColumnsへのクラスタ化インデックスデータ挿入前（別処理）
3. **行1463-1464**: #IndexColumnsへの非クラスタ化インデックスデータ挿入前
4. **行1547-1548**: #IndexSanityへのデータ挿入前
5. **行1865-1866**: #IndexPartitionSanityへのデータ挿入前
6. **行2203-2204**: 追加インデックス情報挿入前
7. **行2269-2270**: #ForeignKeysへのデータ挿入前
8. **行2328-2329**: #UnindexedForeignKeysへのデータ挿入前
9. **行2446-2447**: #Statisticsへのデータ挿入前（パターン1）
10. **行2536-2537**: #Statisticsへのデータ挿入前（パターン2）
11. **行2588**: #ComputedColumnsへのデータ挿入前
12. **行2637-2638**: #TemporalTablesへのデータ挿入前
13. **行3603-3604**: 結果セットクエリ実行前

#### Step 3: 動的SQL構築パターンを理解する

@dsqlへの文字列連結処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sp_BlitzIndex.sql | `sp_BlitzIndex.sql` | SET @dsql = N'...' + ... パターン |

**主要処理フロー**:
- 文字列連結でNULL値が含まれると結果がNULLになる
- QUOTENAME()やCAST()の結果がNULLになる可能性がある

### プログラム呼び出し階層図

```
sp_BlitzIndex
    |
    +-- (各データ取得処理)
            |
            +-- SET @dsql = N'SELECT...' + 動的部分
            |
            +-- IF @dsql IS NULL
            |       |
            |       +-- RAISERROR('@dsql is null', 16, 1)
            |       |
            |       +-- (処理中断)
            |
            +-- (正常時)
                    |
                    +-- RAISERROR('Inserting data into #...', 0, 1)
                    |
                    +-- EXEC sp_executesql @dsql
```

### データフロー図

```
[入力]                         [処理]                    [出力]

@DatabaseName              -->
@SchemaName                --> 動的SQL構築
@TableName                 -->                         --> @dsql
@ObjectID                  -->
QUOTENAME(...)             -->

                              @dsql IS NULL チェック
                                    |
                                    +---> (NULL) RAISERROR --> 処理中断
                                    |
                                    +---> (NOT NULL) sp_executesql --> 結果
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sp_BlitzIndex.sql | `sp_BlitzIndex.sql` | ソース | 本通知を発行するストアドプロシージャ |
| Install-All-Scripts.sql | `Install-All-Scripts.sql` | ソース | sp_BlitzIndexを含むインストールスクリプト |
| Deprecated/sp_BlitzIndex_SQL_Server_2005.sql | `Deprecated/sp_BlitzIndex_SQL_Server_2005.sql` | ソース | 旧バージョン互換版（参考） |
