在多次sp_rename调用后执行SQL脚本的Azure Devops生成任务中止

问题描述 投票:2回答:1

我想构建一个Azure Devops构建任务,该任务针对SQL Server 2017数据库执行SQL脚本列表。我按照本教程来构建任务:https://docs.microsoft.com/en-us/azure/devops/extend/develop/add-build-task?view=azure-devops

该任务通常运行成功,并且我已经对本地数据库(在SQL Server 2017 Express中)执行了各种脚本。我正在使用npm包“ mssql / msnodesqlv8”(mssql的本地SQL Server驱动程序)直接在node.js中连接并执行脚本。

async function executeBatches(script: string, pool: sql.ConnectionPool) {
    const batches = script.split("\r\nGO");
    for (const batch of batches) {
        console.log("Executing script:", batch);
        await pool.batch(batch);
    }
}

现在,我发现一个脚本以非常奇怪的方式失败。有问题的脚本在这样的事务中对4个表执行许多重命名:

BEGIN TRANSACTION
EXEC sp_rename 'table' , 'newTable'
EXEC sp_rename 'newTable.column', 'newColumn', 'COLUMN'
(repeat for several columns)
EXEC sp_rename 'dbo.PK_table', 'PK_newTable'

(repeat for 3 more tables)
COMMIT

在SQL Server Management Studio中,脚本正确执行。但是在Devops任务中,此脚本在大约18次sp_rename调用后中止。没有引发任何错误,并且事务保持打开状态。客户端将继续运行(因为它没有错误),并且在执行更多查询之后,SQL Server将启动回滚,并且当然将回滚自执行此脚本以来的所有更改。

我切换了脚本中的语句,并尝试注释掉了某些行,但是在调用了大约18个sp_rename之后,它总是中止。当我删除足够多的行,以便sp_rename调用少于18个时,任务可以完全运行脚本并提交更改(与哪几行无关)。

[当我删除事务时,它将执行所有重命名直到该神奇数字,然后仍然中止脚本并保留最后一条语句中的隐式事务,因此在进行更多查询后,它仍将回滚所有更改。

我运行了SQL事件探查器,它显示了StmtStarting进行重命名,然后显示BatchCompleted,错误为“ 2-Abort”,但没有其他错误或原因显示该批处理为何被中止。

执行脚本时,system_health会话显示2个错误:

错误#1

带有tds_flags“ DisconnectDueToReadError,NetworkErrorFoundInInputStream,NormalDisconnect的连接错误和tds_input_buffer_error 109。

错误#2

错误代码为5023的安全错误(表示“组或资源未处于执行请求的操作的正确状态。”)

在线搜索这些错误没有给出可用的结果,因为它们要么没有解决方案,要么与登录问题有关,我认为事实并非如此,因为我可以正常执行其他脚本。

我也已经检查过编码,并且已通过节点“ fs”库正确读取了脚本。

非常感谢任何帮助或指向我可以找到导致此问题原因的地方。

编辑:我只用msnodesqlv8就可以构建一个较小的示例。

import tl = require("azure-pipelines-task-lib/task");
import fs = require("fs");
import path = require("path");
import util = require("util");

import { SqlClient } from "msnodesqlv8";
// tslint:disable-next-line: no-var-requires
const sqlClient: SqlClient = require("msnodesqlv8");
const open = util.promisify(sqlClient.open);
const query = util.promisify(sqlClient.query);

async function run() {
    try {
        const scriptDirectory = tl.getInput("ScriptDirectory", true) ?? "";
        const connectionString = "Driver={ODBC Driver 13 for SQL Server};Server={.\\SQLEXPRESS};Uid={sa};Pwd={start};Database={MyDatabase};Encrypt={yes};TrustServerCertificate={yes}";
        const scriptsDir = fs.readdirSync(scriptDirectory);
        const con = await open(connectionString);
        const close = util.promisify(con.close);
        try {
            const conQuery = util.promisify(con.query);
            for (const file of scriptsDir) {
                console.log("Executing:", file);
                const script = readFileWithoutBom(path.join(scriptDirectory, file));
                console.log("Executing script:", script);
                // await query(connectionString, { query_str: script, query_timeout: 120 });
                await conQuery({ query_str: script, query_timeout: 120 });

                const insert = `INSERT INTO AppliedDatabaseScript (ScriptFile, DateApplied) VALUES ('${file}', GETDATE())`
                console.log("Executing script:", insert);
                // await query(connectionString, { query_str: insert });
                await conQuery({ query_str: insert });
            }
        } finally {
            await close();
        }
    }
    catch (err) {
        console.error(err);
        tl.setResult(tl.TaskResult.Failed, err.message);
    }
}

// Strip BOM. SQL Server won't execute certain scripts with BOM.
function readFileWithoutBom(filePath: string) {
   return fs.readFileSync(filePath, "utf-8").replace(/^\uFEFF/, "");
}

行为仍然相同。我尝试使用公共连接和每个查询的单独连接。它将回滚同一连接中的所有内容,并继续进行,就像没有发生错误一样。我还摆弄查询超时,但与错误根本没有关系。

node.js sql-server typescript azure-devops sql-server-2017
1个回答
0
投票

我设法通过切换到非本机驱动程序tedious(也受mssql支持)使其正常工作。似乎用于node.js的本机SQL Server驱动程序无法正常工作。

如果有人在与乏味的连接时遇到问题(由于我无法在线找到合适的文档,这些是基本的配置选项:

{
    user: "username",
    password: "password",
    server: "hostname\\instancename",
    database: "database",
    port: 1433
}

您需要通过在SQL Server配置管理器中激活TCP / IP来确保SQL Server浏览器正在运行,并且实例被配置为可以进行远程访问(即使通过本地主机连接)。

© www.soinside.com 2019 - 2024. All rights reserved.