2

I'm trying to switch one of my VBS scripts from using SQLOLEDB to ODBC driver. So long all works like expected - all but one thing:

When fetching SERVERPROPERTY("is_clustered") from an MSSQL instance the resulting value is different using each driver.

Here's the output of an example script (script follows below):

C:\> cscript test.vbs

Provider: sqloledb

is_clustered (name): is_clustered
is_clustered (type): 12
is_clustered (value): 0

Driver: (SQL Server)

is_clustered (name): is_clustered
is_clustered (type): 204
C:\test.vbs(33, 1) Microsoft VBScript runtime error: Type mismatch

Does anyone know what I'm doing wrong or what I'm missing in my code?

Oh, yes, the code... here's the example script itself:

Option Explicit

Dim RS, CONN1, CONN2

Set RS        = CreateObject("ADODB.Recordset")

Set CONN1      = CreateObject("ADODB.Connection")
CONN1.ConnectionTimeout = 2
CONN1.Provider = "sqloledb"
CONN1.Properties("Integrated Security").Value = "SSPI"
CONN1.Properties("Data Source").Value = "HOSTNAME\INST01"
CONN1.Open

WScript.echo "Provider: sqloledb" & vbLf
RS.Open "SELECT SERVERPROPERTY('IsClustered') AS is_clustered", CONN1
WScript.echo "is_clustered (name): " & RS.fields(0).Name
WScript.echo "is_clustered (type): " & RS.fields(0).Type
WScript.echo "is_clustered (value): " & RS("is_clustered") & vbLf
RS.Close

Set CONN2      = CreateObject("ADODB.Connection")
CONN2.ConnectionTimeout = 2
CONN2.ConnectionString = "driver={SQL Server};" & _
                         "server=HOSTNAME\INST01;" & _
                         "Trusted_Connection=yes"
CONN2.Open

WScript.echo "Driver: (SQL Server)" & vbLf

RS.Open "SELECT SERVERPROPERTY('IsClustered') AS is_clustered", CONN2
WScript.echo "is_clustered (name): " & RS.fields(0).Name
WScript.echo "is_clustered (type): " & RS.fields(0).Type
WScript.echo "is_clustered (value): " & RS("is_clustered")
RS.Close

Many Thanks in advance!

BR, Marcel

Marcel
  • 21
  • 3

1 Answers1

0
Driver SQL Server type OLEDB type ADO type Variant type
SQLOLEDB sql_variant DBTYPE_VARIANT (12) adVariant (12) VT_VARIANT (12)
ODBC varbinary DBTYPE_BYTES (204) adVarBinary (204) n/a

So it looks like the legacy SQLOLEDB is getting the value returned to it as type sql_variant, but when using the legacy ODBC driver it is coming back as varbinary.

This sort of thing isn't unheard of. SQL Server 2005 added varchar(max), varbinary(max), xml, and a few others. ADOdb doesn't understand those types, so you would have to be sure to add an option to your ConnectionString:

Server=hyperion; User ID=ruddiger;Password=hunter2;DataTypeCompatibility=80

This would cause SQL Server for example to return an xml column as ntext

  • OLEDB type: DBTYPE_WSTR (203)
  • ADO type: adLongVarWChar (203)

Because although they created a new OLEDB type for xml:

  • OLEDB type: DBTYPE_XML (141)

ADO was never updated after Windows 2000 to know what DBTYPE of 141 is. So it would throw an error.

There might be something similar happening here with the legacy SQL Server ODBC driver, and there might be an option that needs to be enabled to cause SQL Server to return legacy-compatible data types.

You could also try using the modern, supported, ODBC driver.

Microsoft ODBC Driver 18 for SQL Server

which has a different name from the legacy:

SQL Server

But, i would also recommend not trying to use any ODBC driver. They have a number of won't-fix bugs:

  1. Reading columns out of order returns incorrect values

    It's an optional performance optimization - that nobody needs or wants. ODBC drivers are perfectly free to support reading columns in any order; the Microsoft driver just refuses to because nobody wants to touch the code.

  2. Errors are not raised; but are instead silently eaten

  3. Calling a stored procedure synonym fails

    Except using ODBC Driver to call a synonym procedure fails with:

    The request for procedure '%s' failed because '%s' is a synonym object
    SQLState: 37000
    NativeError: 2809
    The cursor was not declared.
    SQLState: 37000
    NativeError: 16945
    

Do download the latest, supported, and functional, MSOLEDBSQL driver.

You will need to be sure to add the DataTypeCompatibiliy=80 in your ADO connection strings.

Also note this note from Microsoft:

The previous Microsoft OLE DB Provider for SQL Server (SQLOLEDB) and SQL Server Native Client OLE DB provider (SQLNCLI) remains deprecated and it is not recommended to use either for new development work.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • Bug #1 has indeed been fixed in more current versions of the ODBC driver, ref: [here](https://stackoverflow.com/questions/45511013/reading-columns-out-of-order-returns-incorrect-values-sql-server-odbc-driver#comment126440380_46573806). Bug #2 is a matter of not starting stored procedures and anonymous code blocks with `SET NOTOUNT ON;`. – Gord Thompson Mar 19 '22 at 16:10
  • @GordThompson The downside of using `SET NOCOUNT ON` means that the server might not return the number of rows affected. Obviously that's not going to work. – Ian Boyd Mar 19 '22 at 16:54
  • The problem of anonymous code blocks failing silently is that the error is "stuck behind" the rowcount. If we really want to receive the rowcount(s) then we need to check for subsequent results (e.g., by using `.nextset()` with pyodbc in Python) to ensure that we are seeing *all* of them, including any errors that may have occurred. – Gord Thompson Mar 19 '22 at 16:59
  • In our case we're using OLEDB wrapper around ODBC. So, the correct solution is to use the SQL Server OLEDB driver, and **not** use the SQL Server ODBC driver - because the ODBC driver is full of *wontfix* bugs. – Ian Boyd Mar 19 '22 at 18:12