# SQL 模板（`xlyEntry/templesql/`）

框架在 `xlyEntry/src/main/resources/templates/templesql/` 下保存了一小组 **SQL 脚手架**。运行时不会用它们即时生成 SQL；它们是工程师编写新存储过程时复制并填充的模板，最终由框架通过[通用存储过程分发](proc-dispatch.md)调用。

## 已提供的脚手架

实时树中有 8 个文件：

| 文件 | 脚手架内容 |
|---|---|
| `sSaveProName.sql` | 标准保存过程，带约定参数列表和 OUT code |
| `sSaveProNameBefore.sql` | 保存前校验过程 |
| `sDeleteProName.sql` | 标准删除过程 |
| `sProcName.sql` | 通用逻辑过程（审计 / 计算 / 检查） |
| `sButtonParam.sql` | 按钮触发的过程，通过 `gdsconfigformslave.sButtonParam` 参数化 |
| `sp_btn_calc.sql` | 按钮驱动计算过程 |
| `sProTempleByDb.sql` | 按数据库 / 租户切换行为的过程 |
| `sSqlStr.sql` | `gdsconfigformmaster.sSqlStr` 的 SELECT 形状脚手架 |

## 占位符约定

每个脚手架使用 `{placeholderName}` 语法（单花括号，不转义）。来自 `sSaveProName.sql` 的示例：

```sql
DROP PROCEDURE IF EXISTS {sProName};
CREATE PROCEDURE {sProName}(
    IN sGuid VARCHAR(100),
    IN sFormGuid VARCHAR(100),
    IN sLoginId VARCHAR(100),
    IN sBrId VARCHAR(100),
    IN sSuId VARCHAR(100),
    OUT sCode INT(1),
    OUT sReturn LONGTEXT
)
BEGIN
    -- ... placeholder logic ...
    Update {sMasterTableName} AS A
        JOIN {sSlaveTableName} AS B
        ON A.sId = B.sProductId
    SET A.dProductQty = B.dProductQty
    WHERE B.sId = sGuid
      AND B.sBrandsId = sBrId
      AND B.sSubsidiaryId = sSuId;
END
```

工程师复制该文件，填入 `{sProName}`、`{sMasterTableName}`、`{sSlaveTableName}`，把占位逻辑替换成真实业务规则，并将生成的 SQL 应用到目标 schema。

## 占位符用途

- `{sProName}`：过程名，例如 `Sp_Sales_Save`。
- `{sMasterTableName}`、`{sSlaveTableName}`、`{sAllTableName}`：该过程操作的单据表族。
- 其他占位符取决于具体脚手架。

## 为什么这是模板库，不是代码生成器

框架**不会**基于元数据从这些模板自动生成过程。脚手架存在是因为 xly 的过程遵循共同形状；复制脚手架能保证新过程：

- 接受 [通用分发](proc-dispatch.md) 可调用的标准参数列表 `(sGuid, sFormGuid, sLoginId, sBrId, sSuId)`。
- 通过标准 `OUT sCode INT, OUT sReturn LONGTEXT` 返回成功 / 错误。
- 遵守多租户过滤 `sBrandsId = sBrId AND sSubsidiaryId = sSuId`。

不遵守这些约定的过程无法通过通用分发调用，只能从自定义 Java 代码调用。

## 两个 loader

代码库里有**两个**名为 `FileSqlUtil` 的类，但可靠性完全不同：

| Loader | 指向内容 | 状态 |
|---|---|---|
| `xlyFlow/src/main/java/com/xly/sqltemplate/util/FileSqlUtil.java` | 上述 8 个脚手架 | **8 个文件都存在**，这是 BACK 脚本编写页面实际使用的 loader。 |
| `xlyApi/src/main/java/com/xly/api/util/FileSqlUtil.java` | 7 个不同模板常量：`sInSqlStrTemple.sql`、`sOutSqlStrTemple.sql`、`sDataSqlTmpDef.sql`、`sDataSqlTmp.sql`、`sJsonSqlTmp.sql`、`sDbPro.sql`、`sJsonSqlTmpOut.sql` | **这些文件在当前树中都不存在**。这些常量是死代码，可能来自更早的 xlyApi 代码路径。通过它们调用会在运行时报 `FileNotFoundException`。 |

维护人员如果要动 `xlyApi` 的 `FileSqlUtil`，应把它当作默认损坏：要么恢复缺失模板，要么删除这个 loader。

## 另见

- [通用存储过程分发](proc-dispatch.md)：过程写好后框架如何调用。
- [切片 5（每客户 SQL 覆盖）](../../slices/05-customer-sql-override.md)：客户需要替换标准过程时，复用相同模板结构，但在目标 schema 上 `DROP` 并 `CREATE` 一个覆盖版本。
