Sunday, February 19, 2012

Generate Alter Script

Hi,

I read some related threads but none seem to answer my question. How to script a udf or a store procedure that exists in my database as an ALTER script. I don't want to modify the udf to be able to capture it(captureSql). I just want to script it as an ALTER. The scriptingOptions contains the DROP but I did not see the ALTER. I know SSMS does that when I right click on a store procedure I have the option to script it as ALTER.

I am guessing I can get the script then replace the CREATE with ALTER but that does not look to me a good solution. I am hoping there is something in SMO I can use.

Thanks,
Elie

Source Code Sample:

Code Block

using System;

using System.Configuration;

using System.Collections.Generic;

using System.Text;

using Microsoft.SqlServer.Management.Common;

using Microsoft.SqlServer.Management.Smo;

using System.Threading;

using System.Collections.Specialized;

using System.IO;

using System.Text.RegularExpressions;

namespace SMOEvents

{

class SmoEvents

{

private static Server server = null;

private static Database db = null;

private static string folderPath = "";

private static string procedureNamePattern = "";

private static string fileNameExnention = "";

static void Main(string[] args)

{

#region config data

string connString = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).ConnectionStrings.ConnectionStrings["MSSqlServer"].ToString();

System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder(connString);

if (!builder.IntegratedSecurity)

{

SqlConnectionInfo ci = new SqlConnectionInfo(builder.DataSource, builder.UserID, builder.Password);

ServerConnection serverConn = new ServerConnection(ci);

server = new Server(serverConn);

}

else

{

server = new Server(builder.DataSource);

}

if (builder.InitialCatalog != "")

{

db = server.Databases[builder.InitialCatalog];

}

else {

db = server.Databases[0];

}

procedureNamePattern = ConfigurationManager.AppSettings.GetValues("ProcedureNamePattern").GetValue(0).ToString();

folderPath = ConfigurationManager.AppSettings.GetValues("LocalFolderPath").GetValue(0).ToString();

fileNameExnention = ConfigurationManager.AppSettings.GetValues("FileNameExnention").GetValue(0).ToString();

#endregion

if (args.Length > 0)

{

if (args[0].ToString() == "ListenEvents")

{

ListenEvents();

}

else

{

ScriptAllProcedures();

return;

}

}

else {

ScriptAllProcedures();

return;

}

}

private static void ScriptAllProcedures()

{

Regex rx = new Regex(procedureNamePattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);

foreach (StoredProcedure sp in db.StoredProcedures)

{

if ((!sp.IsEncrypted) && (!sp.IsSystemObject) && (rx.IsMatch(sp.Name)))

{

string fileName = folderPath + sp.Schema + "." + sp.Name + fileNameExnention;

ScriptProcedure(sp, fileName);

}

}

}

private static void ScriptProcedure(StoredProcedure sp, string fileName)

{

FileInfo fi = new FileInfo(fileName);

if ((!fi.Exists) ||(fi.Exists && !fi.IsReadOnly))

{

string body = "IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'[" + sp.Schema + "].[" + sp.Name + "]') AND type in (N'P', N'PC'))";

body = body + "\r\n" + " DROP PROCEDURE [" + sp.Schema + "].[" + sp.Name + "]";

body = body + "\r\n" + "GO\n";

body = body + "\r\n" + "SET ANSI_NULLS ON";

body = body + "\r\n" + "GO";

body = body + "\r\n" + "SET QUOTED_IDENTIFIER ON";

body = body + "\r\n" + "GO";

body = body + "\r\n";

body = body + "\r\n" + sp.TextHeader;

body = body + "\r\n" + sp.TextBody;

body = body + "\r\n" + "GO";

body = body + "\r\n";

body = body + "\r\n" + "SET ANSI_NULLS OFF";

body = body + "\r\n" + "GO";

body = body + "\r\n" + "SET QUOTED_IDENTIFIER OFF";

body = body + "\r\n" + "GO";

File.WriteAllText(fileName, body, UnicodeEncoding.Unicode);

Console.WriteLine(@."{0} ", fileName);

}

}

private static void ListenEvents()

{

db.Events.ServerEvent += new ServerEventHandler(Events_ServerEvent);

// DDL events

db.Events.SubscribeToEvents(DatabaseEvent.AlterProcedure + DatabaseEvent.CreateProcedure);

Console.WriteLine(@."Starting events for server: {0}", server.Name);

Console.WriteLine();

Console.WriteLine(@."(Hit Ctrl-C or Ctrl-Break to quit.)");

//Console.WriteLine(@."Press any key to continue.");

//Console.ReadKey();

Console.WriteLine(@."Start listening: {0}", DateTime.Now);

// Start receiving events

db.Events.StartEvents();

// Wait indefinitely for events to occur

Thread.Sleep(Timeout.Infinite);

Console.WriteLine(@."Stop listening ...");

// Unsubscribe from all the events when finished

server.Events.UnsubscribeAllEvents();

}

/// <summary>

/// to avoid Access Denied Error you should execute the following script:

/// ALTER DATABASE [@.dbname] SET SINGLE_USER WITH ROLLBACK IMMEDIATE

/// go

/// ALTER DATABASE [@.dbname] SET ENABLE_BROKER

/// go

/// ALTER DATABASE [@.dbname] SET MULTI_USER

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

static void Events_ServerEvent(object sender, ServerEventArgs e)

{

try

{

if (e.Properties["ObjectName"] != null)

{

StoredProcedure sp = db.StoredProcedures[e.Properties["ObjectName"].Value.ToString()];

if ((!sp.IsEncrypted) && (!sp.IsSystemObject))

{

string fileName = folderPath + sp.Schema + "." + sp.Name + fileNameExnention;

ScriptProcedure(sp, fileName);

}

}

Console.WriteLine(@."EventType: {0, -20} SPID: {1, 4} PostTime: {2, -20}", e.EventType, e.Spid, e.PostTime);

Console.WriteLine();

}

catch (ApplicationException ex)

{

Console.WriteLine(ex.ToString());

}

}

}

}

App.Config Sample:

Code Block

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<appSettings>

<add key="ProcedureNamePattern" value=".+"/>

<add key="FileNameExnention" value=".sql"/>

<add key="LocalFolderPath" value=".\Stored Procedures\"/>

</appSettings>

<connectionStrings>

<add name="MSSqlServer" connectionString="Data Source=.;Integrated Security=true;Initial Catalog=AdventureWorks;" providerName="System.Data.SqlClient" />

</connectionStrings>

</configuration>

|||

Thanks for the code.

I tried the code with the Listenevents option but I am getting an error: ProviderLoadFailure

on this line db.Events.StartEvents();

The ScriptProcedure() does script it as create. But I am looking for a way to be scripted as Alter.

Thanks

Elie

|||

Scripting with CREATE and replacing the CREATE with ALTER I believe is the only way you can get it done with SMO. There is not a native ALTER creation in SMO (that is documented).

|||

Thanks I thought so. I wish I found the documentation.

Elie

No comments:

Post a Comment