'Error when loading datatable with VARCHAR(MAX) column

I have the Powershell following function to load data from a database via ODBC, given a connection string and a query.

function Run-OdbcSQL {
[OutputType([System.Data.DataTable])]
[cmdletbinding()]
param (

        [Parameter(Mandatory)][string]$ConnString,
        [Parameter(Mandatory)][string]$Query
)
    
    $Conn = New-Object System.Data.Odbc.OdbcConnection
    $Conn.ConnectionString = $ConnString
    $Conn.Open()
    try {
        $Result =(New-Object Data.Odbc.OdbcCommand($Query,$Conn)).ExecuteReader()
        
        $Table = New-Object "System.Data.DataTable"
        $Table.Load($Result)
        # Prevent PS from unravelling a table with a single row
        Write-Output -NoEnumerate $Table

    } finally {
        $Conn.Close()
    }
}

This works fine, except when one of the columns being returned, is defined as VARCHAR(MAX). In this case, the function returns the error:

Exception calling "Load" with "1" argument(s): "Failed to enable constraints. 
One or more rows contain values violating non-null, unique, or foreign-key constraints."

If I modify the query to SELECT CAST(column_name AS VARCHAR(255)) FROM …, the data will be loaded without any issue.

Environment:

  • Database: SQL Server 2019
  • ODBC driver: SQL Server Native Client 11.0 / ODBC Driver 18 for SQL Server (reproducible with both)

The issue seems to be a combination of VARCHAR(MAX) and System.Data.DataTable, but I can't figure how to resolve it.



Solution 1:[1]

No definite solution, but I have managed to find some workarounds.

The CAST(<columnname> AS VARCHAR(<length>) works, but you're limited to 8000 characters because "SQL_CHAR and SQL_VARCHAR data types are limited to a maximum length of 8,000 characters" [1][2]

The text datatype on the other hand, can hold 2^30 - 1 bytes (identical to NVARCHAR(MAX)) and it seems to be passed through correctly (couldn't find any concrete info). Thus: `CAST( AS TEXT) avoids the issue.

Test case

  • Data: given a query column defined as VARCHAR(MAX), retrieving a single row where the contents of the column are 100.000 characters long.

  • Middleware: Tests were executed using both ODBC Driver 18 for SQL Server and SQL Server Native Client 11.0. Results were identical for either driver.

  • Database: Microsoft SQL Server 2019.

Query Result
SELECT query Exception calling "Load" with "1" argument(s): "Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints."
SELECT CAST(query as VARCHAR(8000)) OK, truncated at 8.000 characters
SELECT CAST(query as VARCHAR(10000)) The size (10000) given to the type 'varchar' exceeds the maximum allowed for any data type (8000).
SELECT CAST(query as TEXT) OK, 10.000 characters

Remarks

For other databases (using different middleware), this approach might not work. E.g. for PostgreSQL, you need to use the MaxLongVarcharSize property, which is set to 8190 by default, and supports up to 65535 bytes.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DocZerø