Un bug di SQL Server in sp_rename + sp_refreshview

Mi è capitato tempo fa di imbattermi in uno strano comportamento di SQL Server 2008: improvvisamente una view, che nel corso degli anni aveva subito diverse modifiche, è regredita a una versione molto vecchia.
Mi sono arrovellato il cervello nel tentativo, inutile, di cercare una spiegazione al fenomeno, finché esso non si è recentemente manifestato di nuovo e in circostanze fortunate: stavo eseguendo delle operazioni di manutenzione su un database, ed avevo quindi buone possibilità di riprodurre il problema in modo controllato.
Ho ripristinato il database da un backup, e ho rieseguito i pochi comandi impartiti, finché si è manifestato il problema.
Sono così giunto a scoprire che SQL Server 2008 espone un pericoloso bug legato all’uso delle stored procedure di sistema sp_rename e sp_refreshview.
Il problema è già stato isolato e descritto da Davide Mauri.
Riporto qui i dettagli del test che consente di riprodurlo.

Creiamo una view:

create view dbo.a
as
select c = 1
go

Adesso rinominiamola usando sp_rename:

exec sp_rename 'a', 'b'
go

Ricreiamola:

create view dbo.a
as
select c = 2
go

Testiamo, per adesso tutto perfetto:

select * from dbo.a
select * from dbo.b
go

c
-----------
2

(Righe interessate: 1)

c
-----------
1

(Righe interessate: 1)

Ed ora diamo fuoco alle polveri. Eseguiamo sp_refreshview su b:

sp_refreshview 'dbo.b'
go

Testiamo di nuovo:

select * from dbo.a
select * from dbo.b
go

c
-----------
1

(Righe interessate: 1)

c
-----------
1

(Righe interessate: 1)

Facendo il refresh di ‘b’, la definizione di ‘a’ è regredita! Verifichiamo:

sp_helptext 'dbo.a'
go

Text
-----------------------------------------------------------------------------------
create view dbo.a
as
select c = 1

Mauri afferma di aver testato e rilevato il bug in SQL Server 2005, 2008 e 2008 R2. Io personalmente ho potuto verificarlo su SQL Server 2008 SP4.
Come workaround si suggerisce quanto segue:

  • Dopo aver eseguito sp_rename, eseguire una ALTER VIEW manuale sulla view ridenominata:
    alter view dbo.b
    as
    select c = 1
    go
    
  • Evitare di usare sp_rename sulle view. Attenzione: SSMS invoca sp_rename dietro le quinte quando si rinomina una view dalla GUI.

Buon lavoro a tutti e… occhi aperti!