# 通知設計書 21-出力テーブル制限

## 概要

sp_BlitzFirstおよびsp_BlitzCacheプロシージャにおいて、@OutputTableNameパラメータにローカル一時テーブル（#で始まるテーブル）が指定された場合に、グローバル一時テーブル（##で始まるテーブル）のみがサポートされる旨を通知するエラーメッセージの設計書。

### 本通知の処理概要

**業務上の目的・背景**：sp_BlitzFirstおよびsp_BlitzCacheは内部で動的SQLを使用して処理を実行するため、ローカル一時テーブルへの出力ができない。動的SQL内からは呼び出し元のローカル一時テーブルにアクセスできないというSQL Serverの仕様上の制約があるため、この制限が存在する。ユーザーがローカル一時テーブルを指定した際に、適切なエラーメッセージを表示することで、問題の原因と解決策を明確に伝える。

**通知の送信タイミング**：@OutputTableNameパラメータに#で始まるテーブル名（ローカル一時テーブル）が指定され、かつ##で始まらない（グローバル一時テーブルではない）場合に即時発生する。

**通知の受信者**：sp_BlitzFirstまたはsp_BlitzCacheを実行したデータベース管理者、開発者。

**通知内容の概要**：動的SQLの性質上、ローカル一時テーブルはサポートされておらず、グローバル一時テーブル（##で始まるテーブル）を使用する必要がある旨を通知する。

**期待されるアクション**：ユーザーは@OutputTableNameパラメータの値を##で始まるグローバル一時テーブル名に変更するか、永続テーブルを使用するようにパラメータを修正する。

## 通知種別

SQL Serverエラーメッセージ（RAISERROR）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（即時） |
| 優先度 | 高（重大度16） |
| リトライ | 無し |

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

プロシージャを実行したセッションに対して直接エラーメッセージとして送信される。

## 通知テンプレート

### エラーメッセージ

| 項目 | 内容 |
|-----|------|
| メッセージ形式 | RAISERROR |
| 重大度 | 16 |
| 状態 | 0 |

### 本文テンプレート

```
Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| なし | 固定メッセージのため変数なし | - | - |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| プロシージャ実行 | sp_BlitzFirst/sp_BlitzCache実行時 | SUBSTRING(@OutputTableName, 2, 1) = '#' かつ SUBSTRING(@OutputTableName, 2, 2) <> '##' | ローカル一時テーブル指定時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| @OutputTableNameがNULL | 出力テーブルが未指定の場合 |
| @OutputTableNameが永続テーブル | #で始まらない通常テーブルの場合 |
| @OutputTableNameがグローバル一時テーブル | ##で始まるテーブルの場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[プロシージャ実行] --> B{@OutputTableName指定あり?}
    B -->|なし| C[通常処理継続]
    B -->|あり| D{#で始まる?}
    D -->|No| C
    D -->|Yes| E{##で始まる?}
    E -->|Yes| F[グローバル一時テーブルへの出力処理]
    E -->|No| G[RAISERROR発行]
    G --> H[処理中断]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| なし | パラメータ検証のみ | データベースアクセスなし |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | エラー発生時は処理中断 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| パラメータ検証エラー | ローカル一時テーブル指定 | グローバル一時テーブルに変更 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限なし | プロシージャ実行毎に即時発行 |

### 配信時間帯

制限なし（プロシージャ実行時に即時発行）

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

- ユーザー入力のテーブル名がメッセージに直接含まれないため、インジェクションリスクなし
- エラーメッセージには機密情報を含まない

## 備考

- sp_BlitzFirstでは@OutputTableName、@OutputTableNameFileStats、@OutputTableNamePerfmonStats、@OutputTableNameWaitStatsの各パラメータに同様のチェックが適用される
- sp_BlitzCacheでは予約テーブル名（##BlitzCacheProcs、##BlitzCacheResults）のチェックも追加で行われる
- メッセージ内の"Dymamic"は原文ママのスペルミス

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sp_BlitzFirst.sql | `sp_BlitzFirst.sql` | プロシージャ定義とパラメータ宣言を確認 |
| 1-2 | sp_BlitzCache.sql | `sp_BlitzCache.sql` | プロシージャ定義とパラメータ宣言を確認 |

**主要処理フロー**:
1. **行16-21（sp_BlitzFirst.sql）**: @OutputTableName等の出力テーブルパラメータ定義
2. **行3997-4040（sp_BlitzFirst.sql）**: @OutputTableNameの検証とグローバル一時テーブル処理
3. **行8256-8259（sp_BlitzCache.sql）**: @OutputTableNameの検証とエラー発行

#### Step 2: パラメータ検証ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sp_BlitzFirst.sql | `sp_BlitzFirst.sql` | SUBSTRING関数による一時テーブル判定 |

**主要処理フロー**:
- **行3997**: `SUBSTRING(@OutputTableName, 2, 2) = '##'` でグローバル一時テーブルかチェック
- **行4037**: `SUBSTRING(@OutputTableName, 2, 1) = '#'` でローカル一時テーブルを検出
- **行4039**: RAISERRORによるエラーメッセージ発行

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

```
sp_BlitzFirst / sp_BlitzCache
    |
    +-- パラメータ検証
    |       |
    |       +-- SUBSTRING(@OutputTableName, 2, 2) = '##' チェック
    |       |       |
    |       |       +-- Yes: グローバル一時テーブル処理へ
    |       |       +-- No: 次のチェックへ
    |       |
    |       +-- SUBSTRING(@OutputTableName, 2, 1) = '#' チェック
    |               |
    |               +-- Yes: RAISERROR発行（ローカル一時テーブルエラー）
    |               +-- No: 永続テーブル処理へ
    |
    +-- 出力処理
```

### データフロー図

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

@OutputTableName ───> SUBSTRING判定 ───> RAISERROR (エラー時)
                           |
                           +───────────> 動的SQL実行 (正常時)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sp_BlitzFirst.sql | `sp_BlitzFirst.sql` | ソース | 診断結果出力時のテーブル名検証 |
| sp_BlitzCache.sql | `sp_BlitzCache.sql` | ソース | キャッシュ分析結果出力時のテーブル名検証 |
