79

Tôi cần phải thực thi một tập hợp lớn các câu lệnh SQL (tạo ra một loạt các bảng, dạng xem và các thủ tục được lưu trữ) từ trong một chương trình C #.

Các câu lệnh này cần được phân tách bằng các GOcâu lệnh, nhưng SqlCommand.ExecuteNonQuery()không thích các GOcâu lệnh. Giải pháp của tôi, mà tôi cho rằng tôi sẽ đăng để tham khảo, là tách chuỗi SQL trên GOcác dòng và thực hiện riêng từng lô.

Có cách nào dễ dàng hơn / tốt hơn không?

|
98

Sử dụng các đối tượng quản lý máy chủ SQL (SMO) để hiểu các dấu tách GO. Xem bài đăng trên blog của tôi ở đây: http://weblogs.asp.net/jongalloway/Handling-_2200_GO_2200_-Separators-in-Query-Scripts- 2D00 -cách dễ dàng

Mã mẫu:

public static void Main()    
{        
  string scriptDirectory = "c:\\temp\\sqltest\\";
  string sqlConnectionString = "Integrated Security=SSPI;" +
  "Persist Security Info=True;Initial Catalog=Northwind;Data Source=(local)";
  DirectoryInfo di = new DirectoryInfo(scriptDirectory);
  FileInfo[] rgFiles = di.GetFiles("*.sql");
  foreach (FileInfo fi in rgFiles)
  {
        FileInfo fileInfo = new FileInfo(fi.FullName);
        string script = fileInfo.OpenText().ReadToEnd();
        using (SqlConnection connection = new SqlConnection(sqlConnectionString))
        {
            Server server = new Server(new ServerConnection(connection));
            server.ConnectionContext.ExecuteNonQuery(script);
        }
   }
}

Nếu điều đó không hiệu quả với bạn, hãy xem thư viện của Phil Haack, nơi xử lý: http://haacked.com/archive/2007/11/04/a-l Library-for-executing-sql-scripts-with-go-separators -and.aspx

|
  • 1

    Làm thế nào điều này có thể được tích hợp với một giao dịch? Mã này ném một UnlimitedOperationException khi tạo ServerConnection với SqlConnection có giao dịch đang chờ xử lý.

    – Ngô Thiện Bảo 21:51:50 25/05/2009
  • 1

    Giải pháp này hoạt động, tôi chỉ muốn thêm rằng nếu bạn muốn sử dụng các giao dịch với một TransactionScopeđối tượng, bạn chỉ cần tranh thủ kết nối với giao dịch xung quanh hiện tại. Kiểm tra câu trả lời của tôi ở đây: stackoverflow.com/a/18322938/1268570

    – Bùi Bảo Dương 20:57:50 19/08/2013
  • 1

    hoạt động rất tốt, nhưng chúng ta có thể sử dụng SqlConnection.InfoMessage) để xem kết quả trong ứng dụng C # hoặc lưu kết quả trong txttệp, chỉ để biết liệu tập lệnh có được thực thi thành công hay không, bởi vì gần đây sqlcmdtôi đã sử dụng khi tôi thực thi tệp tập lệnh 150 mb trên máy chủ từ xa, sau 55 phút các hàng bị ảnh hưởng với lỗi này TCP Provider: An existing connection was forcibly closed by the remote host., communication link failure. , không có hàng nào bị ảnh hưởng có thể được biết, nhưng tôi lo ngại về các thông báo lỗi trong khi chạy tập tin cơ sở dữ liệu được tạo.

    – Bùi Trúc Vân 08:42:14 06/12/2015
  • 1

    Giải pháp này gây ra lỗi mã của bạn khi một số DLL SQL không được cài đặt trên máy. .NET sử dụng một số dll được tích hợp trong Windows. Sự vắng mặt của một số gói tính năng SQL (bao gồm cả Đối tượng quản lý) có thể ngăn ngừa các lỗi như 'Microsoft.SqlServer.SqlClrProvider.dll' không tìm thấy. Khắc phục sự cố (đây không phải là công việc dễ dàng) lỗi tiếp theo sẽ là 'Microsoft.SqlServer.BathParser.dll', v.v ... Tìm giải pháp khác để đảm bảo tính linh hoạt cho ứng dụng của bạn.

    – Tạ Ðức Phi 06:35:29 27/05/2016
31

Đây là những gì tôi gõ cùng nhau để giải quyết vấn đề trước mắt của tôi.

private void ExecuteBatchNonQuery(string sql, SqlConnection conn) {
    string sqlBatch = string.Empty;
    SqlCommand cmd = new SqlCommand(string.Empty, conn);
    conn.Open();
    sql += "\nGO";   // make sure last batch is executed.
    try {
        foreach (string line in sql.Split(new string[2] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries)) {
            if (line.ToUpperInvariant().Trim() == "GO") {
                cmd.CommandText = sqlBatch;
                cmd.ExecuteNonQuery();
                sqlBatch = string.Empty;
            } else {
                sqlBatch += line + "\n";
            }
        }            
    } finally {
        conn.Close();
    }
}

Nó yêu cầu các lệnh GO nằm trên dòng riêng của chúng và sẽ không phát hiện các bình luận khối, do đó loại điều này sẽ bị phân tách và gây ra lỗi:

ExecuteBatchNonQuery(@"
    /*
    GO
    */", conn);
|
  • 1

    Thật tuyệt khi tôi có thể dễ dàng điều chỉnh nó với SqlCe nếu cần - mã khác sử dụng các lớp và lệnh kết nối Sql.

    – Ngô Thiện Bảo 23:22:08 31/07/2012
  • 1

    Tôi muốn chạy mã này với tập lệnh SQL với một số thủ tục được lưu trữ bên trong, nhưng tôi hơi bối rối, nó đọc SQL ở đâu? Khi bạn đề cập đến 'đợt cuối', ý bạn là mã SQL? Và nếu vậy, làm thế nào bạn xác định được đợt cuối cùng, và nếu tôi muốn chạy tất cả các đợt không chỉ là đợt cuối thì sao? Tôi biết quá nhiều câu hỏi, nhưng cảm ơn nếu bạn có thời gian trả lời.

    – Bùi Bảo Dương 15:54:42 18/12/2013
  • 1

    Bạn truyền SQL cho hàm dưới dạng một chuỗi: string sql- đó là toàn bộ tập lệnh. Khi tôi đề cập đến một "đợt", tôi có nghĩa là một đoạn mã SQL giữa hai câu lệnh "GO". Mã thêm một GOphần cuối của tập lệnh để mã bên trong foreachsẽ không bỏ qua đợt cuối nếu bạn không kết thúc tập lệnh của mình bằng a GO. Vì vậy, mã như được viết sẽ thực thi tất cả các SQL.

    – Bùi Trúc Vân 19:33:52 18/12/2013
  • 1

    Tôi đã tạo một phương thức mở rộng: lớp tĩnh bên trong SqlCommandHelper {Internal static void ExecuteBatchNonQuery (chuỗi này SqlCommand, chuỗi sql)

    – Tạ Ðức Phi 15:05:18 15/05/2014
  • 1

    Nếu bạn muốn trở nên hiệu quả hơn một chút, bạn có thể sử dụng StringBuilder sqlBatchthay thế.

    – Hoàng Tường Phát 10:32:21 19/03/2015
9

Bạn có thể sử dụng các đối tượng quản lý SQL để thực hiện điều này. Đây là những đối tượng tương tự mà Management Studio sử dụng để thực hiện các truy vấn. Tôi tin rằng Server.ConnectionContext.ExecuteNonQuery()sẽ thực hiện những gì bạn cần.

|
6

Từ khóa phân tách lô "GO" thực sự được sử dụng bởi chính SQL Management Studio, để nó biết nơi chấm dứt các lô mà nó đang gửi đến máy chủ và nó không được chuyển đến máy chủ SQL. Bạn thậm chí có thể thay đổi từ khóa trong Management Studio, nếu bạn mong muốn như vậy.

|
4

Dựa trên giải pháp của Blorgbeard.

foreach (var sqlBatch in commandText.Split(new[] { "GO" }, StringSplitOptions.RemoveEmptyEntries))
{
   sqlCommand.CommandText = sqlBatch;
   sqlCommand.ExecuteNonQuery();
}
|
3

Nếu bạn không muốn sử dụng SMO, ví dụ vì bạn cần phải đa nền tảng, bạn cũng có thể sử dụng lớp ScriptSplitter từ SubText.

Đây là cách triển khai trong C # & VB.NET

Sử dụng:

    string strSQL = @"
SELECT * FROM INFORMATION_SCHEMA.columns
GO
SELECT * FROM INFORMATION_SCHEMA.views
";

    foreach(string Script in new Subtext.Scripting.ScriptSplitter(strSQL ))
    {
        Console.WriteLine(Script);
    }

Nếu bạn gặp vấn đề với các bình luận kiểu c đa dòng, hãy xóa các bình luận bằng regex:

static string RemoveCstyleComments(string strInput)
{
    string strPattern = @"/[*][\w\d\s]+[*]/";
    //strPattern = @"/\*.*?\*/"; // Doesn't work
    //strPattern = "/\\*.*?\\*/"; // Doesn't work
    //strPattern = @"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/ "; // Doesn't work
    //strPattern = @"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/ "; // Doesn't work

    // http://stackoverflow.com/questions/462843/improving-fixing-a-regex-for-c-style-block-comments
    strPattern = @"/\*(?>(?:(?>[^*]+)|\*(?!/))*)\*/";  // Works !

    string strOutput = System.Text.RegularExpressions.Regex.Replace(strInput, strPattern, string.Empty, System.Text.RegularExpressions.RegexOptions.Multiline);
    Console.WriteLine(strOutput);
    return strOutput;
} // End Function RemoveCstyleComments

Xóa các nhận xét một dòng ở đây:

https://stackoverflow.com/questions/9842991/regex-to-remove-single-line-sql-comments
|
3

Nếu bạn không muốn cài đặt các đối tượng SMO, bạn có thể sử dụng công cụ gplex (xem câu trả lời này )

|
2

Tôi đã xem xét điều này một vài lần khi kết thúc quyết định với việc triển khai EF Một chút sửa đổi choSqlConnection

public static void ExecuteSqlScript(this SqlConnection sqlConnection, string sqlBatch)
        {
            // Handle backslash utility statement (see http://technet.microsoft.com/en-us/library/dd207007.aspx)
            sqlBatch = Regex.Replace(sqlBatch, @"\\(\r\n|\r|\n)", string.Empty);

            // Handle batch splitting utility statement (see http://technet.microsoft.com/en-us/library/ms188037.aspx)
            var batches = Regex.Split(
                sqlBatch,
                string.Format(CultureInfo.InvariantCulture, @"^\s*({0}[ \t]+[0-9]+|{0})(?:\s+|$)", BatchTerminator),
                RegexOptions.IgnoreCase | RegexOptions.Multiline);

            for (int i = 0; i < batches.Length; ++i)
            {
                // Skip batches that merely contain the batch terminator
                if (batches[i].StartsWith(BatchTerminator, StringComparison.OrdinalIgnoreCase) ||
                    (i == batches.Length - 1 && string.IsNullOrWhiteSpace(batches[i])))
                {
                    continue;
                }

                // Include batch terminator if the next element is a batch terminator
                if (batches.Length > i + 1 &&
                    batches[i + 1].StartsWith(BatchTerminator, StringComparison.OrdinalIgnoreCase))
                {
                    int repeatCount = 1;

                    // Handle count parameter on the batch splitting utility statement
                    if (!string.Equals(batches[i + 1], BatchTerminator, StringComparison.OrdinalIgnoreCase))
                    {
                        repeatCount = int.Parse(Regex.Match(batches[i + 1], @"([0-9]+)").Value, CultureInfo.InvariantCulture);
                    }

                    for (int j = 0; j < repeatCount; ++j)
                    {
                       var command = sqlConnection.CreateCommand();
                       command.CommandText = batches[i];
                       command.ExecuteNonQuery();
                    }
                }
                else
                {
                    var command = sqlConnection.CreateCommand();
                    command.CommandText = batches[i];
                    command.ExecuteNonQuery();
                }
            }
        }
|
  • 1

    Cảm ơn bạn @Filip Cordas. Mặc dù điều này không được đánh dấu là một câu trả lời nhưng điều này đã giúp tôi như một cơ duyên! Chúng tôi có số lượng lớn các tập lệnh trong đó BatchTerminator đã được đề cập đến các cách khác nhau như kết hợp các chữ hoa và chữ thường (go, Go, GO, v.v.) và thời gian tối đa có dấu vết hoặc khoảng trống dẫn đến nó gây ra vấn đề lớn khi thực hiện thông qua c # ... . Cảm ơn bạn !!

    – Lý Nhật Hùng 11:00:12 03/04/2019
  • 1

    @DipakRiswadkar Có khóa trong câu hỏi này một vài lần và không có câu trả lời nào được cung cấp đáp ứng nhu cầu của tôi, vì vậy nhìn vào triển khai của EF có vẻ tốt nên tôi đã đăng câu trả lời.

    – Tạ Khắc Tuấn 17:42:13 05/04/2019
2

Nếu bạn không muốn sử dụng SMO (tốt hơn giải pháp bên dưới, nhưng tôi muốn đưa ra một giải pháp thay thế ...), bạn có thể chia truy vấn của mình với chức năng này.

Nó là:

  • Nhận xét bằng chứng (ví dụ --GO hoặc / * GO * /)
  • Chỉ hoạt động trên một dòng mới, giống như trong SSMS (ví dụ / * test / * GO hoạt động và chọn 1 là không đi
  • Chứng minh chuỗi (ví dụ in 'không đi')

    private List<string> SplitScriptGo(string script)
    {
        var result = new List<string>();
        int pos1 = 0;
        int pos2 = 0;
        bool whiteSpace = true;
        bool emptyLine = true;
        bool inStr = false;
        bool inComment1 = false;
        bool inComment2 = false;
    
        while (true)
        {
            while (pos2 < script.Length && Char.IsWhiteSpace(script[pos2]))
            {
                if (script[pos2] == '\r' || script[pos2] == '\n')
                {
                    emptyLine = true;
                    inComment1 = false;
                }
    
                pos2++;
            }
    
            if (pos2 == script.Length)
                break;
    
            bool min2 = (pos2 + 1) < script.Length;
            bool min3 = (pos2 + 2) < script.Length;
    
            if (!inStr && !inComment2 && min2 && script.Substring(pos2, 2) == "--")
                inComment1 = true;
    
            if (!inStr && !inComment1 && min2 && script.Substring(pos2, 2) == "/*")
                inComment2 = true;
    
            if (!inComment1 && !inComment2 && script[pos2] == '\'')
                inStr = !inStr;
    
            if (!inStr && !inComment1 && !inComment2 && emptyLine
                && (min2 && script.Substring(pos2, 2).ToLower() == "go")
                && (!min3 || char.IsWhiteSpace(script[pos2 + 2]) || script.Substring(pos2 + 2, 2) == "--" || script.Substring(pos2 + 2, 2) == "/*"))
            {
                if (!whiteSpace)
                    result.Add(script.Substring(pos1, pos2 - pos1));
    
                whiteSpace = true;
                emptyLine = false;
                pos2 += 2;
                pos1 = pos2;
            }
            else
            {
                pos2++;
                whiteSpace = false;
    
                if (!inComment2)
                    emptyLine = false;
            }
    
            if (!inStr && inComment2 && pos2 > 1 && script.Substring(pos2 - 2, 2) == "*/")
                inComment2 = false;
        }
    
        if (!whiteSpace)
            result.Add(script.Substring(pos1));
    
        return result;
    }
|
2

Tôi đã thực hiện điều này ngày hôm nay bằng cách tải SQL của tôi từ một tệp văn bản thành một chuỗi. Sau đó tôi đã sử dụng hàm Split chuỗi để tách chuỗi thành các lệnh riêng lẻ sau đó được gửi đến máy chủ riêng lẻ. Đơn giản :)

Chỉ cần nhận ra rằng bạn cần phải phân tách trên \ nGO chỉ trong trường hợp các chữ GO xuất hiện trong bất kỳ tên bảng nào của bạn, v.v ... Đoán tôi đã may mắn ở đó!

|
2

Nếu bạn không muốn đi theo con đường SMO, bạn có thể tìm kiếm và thay thế "GO" cho ";" và truy vấn như bạn muốn. Lưu ý rằng soly tập kết quả cuối cùng sẽ được trả về.

|
2

Tôi cũng gặp phải vấn đề tương tự và tôi không thể tìm thấy bất kỳ cách nào khác ngoài việc tách hoạt động SQL đơn lẻ thành các tệp riêng biệt, sau đó thực hiện tất cả chúng theo trình tự.

Rõ ràng vấn đề không nằm ở danh sách các lệnh DML, chúng có thể được thực thi mà không có GO ở giữa; câu chuyện khác với DDL (tạo, thay đổi, thả ...)

|
1

sử dụng phương pháp sau để phân tách chuỗi và thực thi từng đợt

using System;
using System.IO;
using System.Text.RegularExpressions;
namespace RegExTrial
{
    class Program
    {
        static void Main(string[] args)
        {
            string sql = String.Empty;
            string path=@"D:\temp\sample.sql";
            using (StreamReader reader = new StreamReader(path)) {
                sql = reader.ReadToEnd();
            }            
            //Select any GO (ignore case) that starts with at least 
            //one white space such as tab, space,new line, verticle tab etc
            string pattern="[\\s](?i)GO(?-i)";

            Regex matcher = new Regex(pattern, RegexOptions.Compiled);
            int start = 0;
            int end = 0;
            Match batch=matcher.Match(sql);
            while (batch.Success) {
                end = batch.Index;
                string batchQuery = sql.Substring(start, end - start).Trim();
                //execute the batch
                ExecuteBatch(batchQuery);
                start = end + batch.Length;
                batch = matcher.Match(sql,start);
            }

        }

        private static void ExecuteBatch(string command)
        { 
            //execute your query here
        }

    }
}
|
0

Đối với bất cứ ai vẫn có vấn đề. Bạn có thể sử dụng Microsoft SMO chính thức

https://docs.microsoft.com/en-us/sql/relational-database/server-manloyment-objects-smo/overview-smo?view=sql-server-2017

using (var connection = new SqlConnection(connectionString))
{
  var server = new Server(new ServerConnection(connection));
  server.ConnectionContext.ExecuteNonQuery(sql);
}
|
  • 1

    Điều này không thêm bất cứ điều gì qua câu trả lời được bình chọn, được chấp nhận hàng đầu, cũng gợi ý SMO (được đăng 10 năm trước!).

    – Tạ Ái Vân 21:34:51 10/04/2019
0

Để tránh các bên thứ ba, biểu thức chính quy, chi phí bộ nhớ và làm việc nhanh với các tập lệnh lớn, tôi đã tạo trình phân tích cú pháp dựa trên luồng của riêng mình.

  • kiểm tra cú pháp trước
  • có thể nhận ra ý kiến ​​với - hoặc / ** /

    -- some commented text
     /*
    drop table Users;
    GO
       */
  • có thể nhận ra chuỗi ký tự bằng 'hoặc "

    set @s =
        'create table foo(...);
        GO
        create index ...';
  • giữ nguyên định dạng LF và CR
  • bảo tồn khối ý kiến ​​trong các đối tượng (thủ tục lưu trữ, khung nhìn, v.v.)
  • và các công trình khác như

          gO -- commented text

Cách sử dụng

    try
    {
        using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Persist Security Info=True;Initial Catalog=DATABASE-NAME;Data Source=SERVER-NAME"))
        {
            connection.Open();

            int rowsAffected = SqlStatementReader.ExecuteSqlFile(
                "C:\\target-sql-script.sql",
                connection,
                // Don't forget to use the correct file encoding!!!
                Encoding.Default,
                // Indefinitely (sec)
                0
            );
        }
    }
    // implement your handlers
    catch (SqlStatementReader.SqlBadSyntaxException) { }
    catch (SqlException) { }
    catch (Exception) { }

Trình đọc tập lệnh SQL dựa trên luồng

class SqlStatementReader
{
    public class SqlBadSyntaxException : Exception
    {
        public SqlBadSyntaxException(string description) : base(description) { }
        public SqlBadSyntaxException(string description, int line) : base(OnBase(description, line, null)) { }
        public SqlBadSyntaxException(string description, int line, string filePath) : base(OnBase(description, line, filePath)) { }
        private static string OnBase(string description, int line, string filePath)
        {
            if (filePath == null)
                return string.Format("Line: {0}. {1}", line, description);
            else
                return string.Format("File: {0}\r\nLine: {1}. {2}", filePath, line, description);
        }
    }

    enum SqlScriptChunkTypes
    {
        InstructionOrUnquotedIdentifier = 0,
        BracketIdentifier = 1,
        QuotIdentifierOrLiteral = 2,
        DblQuotIdentifierOrLiteral = 3,
        CommentLine = 4,
        CommentMultiline = 5,
    }

    StreamReader _sr = null;
    string _filePath = null;
    int _lineStart = 1;
    int _lineEnd = 1;
    bool _isNextChar = false;
    char _nextChar = '\0';

    public SqlStatementReader(StreamReader sr)
    {
        if (sr == null)
            throw new ArgumentNullException("StreamReader can't be null.");

        if (sr.BaseStream is FileStream)
            _filePath = ((FileStream)sr.BaseStream).Name;

        _sr = sr;
    }

    public SqlStatementReader(StreamReader sr, string filePath)
    {
        if (sr == null)
            throw new ArgumentNullException("StreamReader can't be null.");

        _sr = sr;
        _filePath = filePath;
    }

    public int LineStart { get { return _lineStart; } }
    public int LineEnd { get { return _lineEnd == 1 ? _lineEnd : _lineEnd - 1; } }

    public void LightSyntaxCheck()
    {
        while (ReadStatementInternal(true) != null) ;
    }

    public string ReadStatement()
    {
        for (string s = ReadStatementInternal(false); s != null; s = ReadStatementInternal(false))
        {
            // skip empty
            for (int i = 0; i < s.Length; i++)
            {
                switch (s[i])
                {
                    case ' ': continue;
                    case '\t': continue;
                    case '\r': continue;
                    case '\n': continue;
                    default:
                        return s;
                }
            }
        }
        return null;
    }

    string ReadStatementInternal(bool syntaxCheck)
    {
        if (_isNextChar == false && _sr.EndOfStream)
            return null;

        StringBuilder allLines = new StringBuilder();
        StringBuilder line = new StringBuilder();
        SqlScriptChunkTypes nextChunk = SqlScriptChunkTypes.InstructionOrUnquotedIdentifier;
        SqlScriptChunkTypes currentChunk = SqlScriptChunkTypes.InstructionOrUnquotedIdentifier;
        char ch = '\0';
        int lineCounter = 0;
        int nextLine = 0;
        int currentLine = 0;
        bool nextCharHandled = false;
        bool foundGO;
        int go = 1;

        while (ReadChar(out ch))
        {
            if (nextCharHandled == false)
            {
                currentChunk = nextChunk;
                currentLine = nextLine;

                switch (currentChunk)
                {
                    case SqlScriptChunkTypes.InstructionOrUnquotedIdentifier:

                        if (ch == '[')
                        {
                            currentChunk = nextChunk = SqlScriptChunkTypes.BracketIdentifier;
                            currentLine = nextLine = lineCounter;
                        }
                        else if (ch == '"')
                        {
                            currentChunk = nextChunk = SqlScriptChunkTypes.DblQuotIdentifierOrLiteral;
                            currentLine = nextLine = lineCounter;
                        }
                        else if (ch == '\'')
                        {
                            currentChunk = nextChunk = SqlScriptChunkTypes.QuotIdentifierOrLiteral;
                            currentLine = nextLine = lineCounter;
                        }
                        else if (ch == '-' && (_isNextChar && _nextChar == '-'))
                        {
                            nextCharHandled = true;
                            currentChunk = nextChunk = SqlScriptChunkTypes.CommentLine;
                            currentLine = nextLine = lineCounter;
                        }
                        else if (ch == '/' && (_isNextChar && _nextChar == '*'))
                        {
                            nextCharHandled = true;
                            currentChunk = nextChunk = SqlScriptChunkTypes.CommentMultiline;
                            currentLine = nextLine = lineCounter;
                        }
                        else if (ch == ']')
                        {
                            throw new SqlBadSyntaxException("Incorrect syntax near ']'.", _lineEnd + lineCounter, _filePath);
                        }
                        else if (ch == '*' && (_isNextChar && _nextChar == '/'))
                        {
                            throw new SqlBadSyntaxException("Incorrect syntax near '*'.", _lineEnd + lineCounter, _filePath);
                        }
                        break;

                    case SqlScriptChunkTypes.CommentLine:

                        if (ch == '\r' && (_isNextChar && _nextChar == '\n'))
                        {
                            nextCharHandled = true;
                            currentChunk = nextChunk = SqlScriptChunkTypes.InstructionOrUnquotedIdentifier;
                            currentLine = nextLine = lineCounter;
                        }
                        else if (ch == '\n' || ch == '\r')
                        {
                            currentChunk = nextChunk = SqlScriptChunkTypes.InstructionOrUnquotedIdentifier;
                            currentLine = nextLine = lineCounter;
                        }
                        break;

                    case SqlScriptChunkTypes.CommentMultiline:

                        if (ch == '*' && (_isNextChar && _nextChar == '/'))
                        {
                            nextCharHandled = true;
                            nextChunk = SqlScriptChunkTypes.InstructionOrUnquotedIdentifier;
                            nextLine = lineCounter;
                        }
                        else if (ch == '/' && (_isNextChar && _nextChar == '*'))
                        {
                            throw new SqlBadSyntaxException("Missing end comment mark '*/'.", _lineEnd + currentLine, _filePath);
                        }
                        break;

                    case SqlScriptChunkTypes.BracketIdentifier:

                        if (ch == ']')
                        {
                            nextChunk = SqlScriptChunkTypes.InstructionOrUnquotedIdentifier;
                            nextLine = lineCounter;
                        }
                        break;

                    case SqlScriptChunkTypes.DblQuotIdentifierOrLiteral:

                        if (ch == '"')
                        {
                            if (_isNextChar && _nextChar == '"')
                            {
                                nextCharHandled = true;
                            }
                            else
                            {
                                nextChunk = SqlScriptChunkTypes.InstructionOrUnquotedIdentifier;
                                nextLine = lineCounter;
                            }
                        }
                        break;

                    case SqlScriptChunkTypes.QuotIdentifierOrLiteral:

                        if (ch == '\'')
                        {
                            if (_isNextChar && _nextChar == '\'')
                            {
                                nextCharHandled = true;
                            }
                            else
                            {
                                nextChunk = SqlScriptChunkTypes.InstructionOrUnquotedIdentifier;
                                nextLine = lineCounter;
                            }
                        }
                        break;
                }
            }
            else
                nextCharHandled = false;

            foundGO = false;
            if (currentChunk == SqlScriptChunkTypes.InstructionOrUnquotedIdentifier || go >= 5 || (go == 4 && currentChunk == SqlScriptChunkTypes.CommentLine))
            {
                // go = 0 - break, 1 - begin of the string, 2 - spaces after begin of the string, 3 - G or g, 4 - O or o, 5 - spaces after GO, 6 - line comment after valid GO
                switch (go)
                {
                    case 0:
                        if (ch == '\r' || ch == '\n')
                            go = 1;
                        break;
                    case 1:
                        if (ch == ' ' || ch == '\t')
                            go = 2;
                        else if (ch == 'G' || ch == 'g')
                            go = 3;
                        else if (ch != '\n' && ch != '\r')
                            go = 0;
                        break;
                    case 2:
                        if (ch == 'G' || ch == 'g')
                            go = 3;
                        else if (ch == '\n' || ch == '\r')
                            go = 1;
                        else if (ch != ' ' && ch != '\t')
                            go = 0;
                        break;
                    case 3:
                        if (ch == 'O' || ch == 'o')
                            go = 4;
                        else if (ch == '\n' || ch == '\r')
                            go = 1;
                        else
                            go = 0;
                        break;
                    case 4:
                        if (ch == '\r' && (_isNextChar && _nextChar == '\n'))
                            go = 5;
                        else if (ch == '\n' || ch == '\r')
                            foundGO = true;
                        else if (ch == ' ' || ch == '\t')
                            go = 5;
                        else if (ch == '-' && (_isNextChar && _nextChar == '-'))
                            go = 6;
                        else
                            go = 0;
                        break;
                    case 5:
                        if (ch == '\r' && (_isNextChar && _nextChar == '\n'))
                            go = 5;
                        else if (ch == '\n' || ch == '\r')
                            foundGO = true;
                        else if (ch == '-' && (_isNextChar && _nextChar == '-'))
                            go = 6;
                        else if (ch != ' ' && ch != '\t')
                            throw new SqlBadSyntaxException("Incorrect syntax was encountered while parsing go.", _lineEnd + lineCounter, _filePath);
                        break;
                    case 6:
                        if (ch == '\r' && (_isNextChar && _nextChar == '\n'))
                            go = 6;
                        else if (ch == '\n' || ch == '\r')
                            foundGO = true;
                        break;
                    default:
                        go = 0;
                        break;
                }
            }
            else
                go = 0;

            if (foundGO)
            {
                if (ch == '\r' || ch == '\n')
                {
                    ++lineCounter;
                }
                // clear GO
                string s = line.Append(ch).ToString();
                for (int i = 0; i < s.Length; i++)
                {
                    switch (s[i])
                    {
                        case ' ': continue;
                        case '\t': continue;
                        case '\r': continue;
                        case '\n': continue;
                        default:
                            _lineStart = _lineEnd;
                            _lineEnd += lineCounter;
                            return allLines.Append(s.Substring(0, i)).ToString();
                    }
                }
                return string.Empty;
            }

            // accumulate by string
            if (ch == '\r' && (_isNextChar == false || _nextChar != '\n'))
            {
                ++lineCounter;
                if (syntaxCheck == false)
                    allLines.Append(line.Append('\r').ToString());
                line.Clear();
            }
            else if (ch == '\n')
            {
                ++lineCounter;
                if (syntaxCheck == false)
                    allLines.Append(line.Append('\n').ToString());
                line.Clear();
            }
            else
            {
                if (syntaxCheck == false)
                    line.Append(ch);
            }
        }

        // this is the end of the stream, return it without GO, if GO exists
        switch (currentChunk)
        {
            case SqlScriptChunkTypes.InstructionOrUnquotedIdentifier:
            case SqlScriptChunkTypes.CommentLine:
                break;
            case SqlScriptChunkTypes.CommentMultiline:
                if (nextChunk != SqlScriptChunkTypes.InstructionOrUnquotedIdentifier)
                    throw new SqlBadSyntaxException("Missing end comment mark '*/'.", _lineEnd + currentLine, _filePath);
                break;
            case SqlScriptChunkTypes.BracketIdentifier:
                if (nextChunk != SqlScriptChunkTypes.InstructionOrUnquotedIdentifier)
                    throw new SqlBadSyntaxException("Unclosed quotation mark [.", _lineEnd + currentLine, _filePath);
                break;
            case SqlScriptChunkTypes.DblQuotIdentifierOrLiteral:
                if (nextChunk != SqlScriptChunkTypes.InstructionOrUnquotedIdentifier)
                    throw new SqlBadSyntaxException("Unclosed quotation mark \".", _lineEnd + currentLine, _filePath);
                break;
            case SqlScriptChunkTypes.QuotIdentifierOrLiteral:
                if (nextChunk != SqlScriptChunkTypes.InstructionOrUnquotedIdentifier)
                    throw new SqlBadSyntaxException("Unclosed quotation mark '.", _lineEnd + currentLine, _filePath);
                break;
        }

        if (go >= 4)
        {
            string s = line.ToString();
            for (int i = 0; i < s.Length; i++)
            {
                switch (s[i])
                {
                    case ' ': continue;
                    case '\t': continue;
                    case '\r': continue;
                    case '\n': continue;
                    default:
                        _lineStart = _lineEnd;
                        _lineEnd += lineCounter + 1;
                        return allLines.Append(s.Substring(0, i)).ToString();
                }
            }
        }

        _lineStart = _lineEnd;
        _lineEnd += lineCounter + 1;
        return allLines.Append(line.ToString()).ToString();
    }

    bool ReadChar(out char ch)
    {
        if (_isNextChar)
        {
            ch = _nextChar;
            if (_sr.EndOfStream)
                _isNextChar = false;
            else
                _nextChar = Convert.ToChar(_sr.Read());
            return true;
        }
        else if (_sr.EndOfStream == false)
        {
            ch = Convert.ToChar(_sr.Read());
            if (_sr.EndOfStream == false)
            {
                _isNextChar = true;
                _nextChar = Convert.ToChar(_sr.Read());
            }
            return true;
        }
        else
        {
            ch = '\0';
            return false;
        }
    }

    public static int ExecuteSqlFile(string filePath, SqlConnection connection, Encoding fileEncoding, int commandTimeout)
    {
        int rowsAffected = 0;
        using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            // Simple syntax check (you can comment out these two lines below)
            new SqlStatementReader(new StreamReader(fs, fileEncoding)).LightSyntaxCheck();
            fs.Seek(0L, SeekOrigin.Begin);

            // Read statements without GO
            SqlStatementReader rd = new SqlStatementReader(new StreamReader(fs, fileEncoding));
            string stmt;
            while ((stmt = rd.ReadStatement()) != null)
            {
                using (SqlCommand cmd = connection.CreateCommand())
                {
                    cmd.CommandText = stmt;
                    cmd.CommandTimeout = commandTimeout;
                    int i = cmd.ExecuteNonQuery();
                    if (i > 0)
                        rowsAffected += i;
                }
            }
        }
        return rowsAffected;
    }
}
|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.