coldfusioncoldfusion-10

What are the details for using CF_SQL_NVARCHAR in ColdFusion 10?


The ColdFusion 10 documentation on Updating Your Database has a section on Database-related enhancements in ColdFusion 10. That page mentions that there is now support for CF_SQL_NVARCHAR among others, but with no details about them. Additionally, the cfqueryparam documentation hasn't been updated to include their existence.

The ColdFusion 9 documentation for cfqueryparam mentions that CF_SQL_VARCHAR maps to varchar in MSSQL. This is true unless the ColdFusion Administrator datasource settings has the String Format setting enabled. In which case CF_SQL_VARCHAR maps to nvarchar. This poorly documented feature is a hack which can cause performance issues within ColdFusion.

So it's great that they have introduced CF_SQL_NVARCHAR, but it would be good to understand how it works. It is simply an alias for CF_SQL_VARCHAR making it pointless? Does it always send strings as nvarchar? If so, does CF_SQL_VARCHAR always send in varchar?

I would hope that for backward compatibility's sake it is implemented as such:

If String Format is enabled CF_SQL_VARCHAR and CF_SQL_NVARCHAR both map to nvarchar.

If String Format is disabled then CF_SQL_VARCHAR maps to varchar and CF_SQL_NVARCHAR maps to nvarchar.

This would mean any pre-CF10 sites can move to CF10 and work, with the same performance considerations pre-CF10.

New sites, or sites that rewrite all queries to match CF_SQL_VARCHAR and CF_SQL_NVARCHAR with the database design will not get the performance penalty that is unavoidable pre-CF10.

Can anyone confirm if this is the case; even better if with something official?


Solution

  • While you are waiting for something more official, I will throw in my $0.02 ...

    I did some digging and based on my observations (with an MS SQL datasource) I believe that:

    CF_SQL_NVARCHAR Test/Results:

    If you enable datasource logging, you can see the driver invokes the special setNString method whenever CF_SQL_NVARCHAR is used. So ultimately the value is sent to the database as nvarchar. (You can confirm this with a SQL Profiler)

        // Query
        SELECT  ID
        FROM    Test
        WHERE   NVarcharColumn = <cfqueryparam value="#form.value#" cfsqltype="cf_sql_nvarchar">
    
        // Log 
        spy(...)>> PreparedStatement[9].setNString(int parameterIndex, String value)
    
        // Profiler
        exec sp_prepexec @p1 output,N'@P1 nvarchar(4000)',N'SELECT  ID
                FROM    Test
                WHERE   NVarcharColumn = @P1 ',N'Стоял он, дум великих полн'
    

    CF_SQL_VARCHAR Test/Results:

    In the case of CF_SQL_VARCHAR, it is technically flagged as varchar. However, the String Format setting ultimately controls how it is handled by the database. When the setting is enabled, it is handled as nvarchar. When it is disabled, it is treated as varchar. Again, you can verify this with a SQL Profiler.

    Bottom line, everything I have seen so far says you are right on target about the implementation.

        // Query
        SELECT  ID
        FROM    Test
        WHERE   PlainVarcharColumn = <cfqueryparam value="#form.value#" cfsqltype="cf_sql_varchar">
    
        // Log
        spy(..)>> PreparedStatement[8].setObject(int parameterIndex, Object x, int targetSqlType)
        spy(..)>> parameterIndex = 1
        spy(..)>> x = ????? ??, ??? ??????? ????
        spy(..)>> targetSqlType = 12  (ie CF_SQL_VARCHAR)
    
        // Profiler (Setting ENABLED)
        exec sp_prepexec @p1 output,N'@P1 nvarchar(4000)',N'SELECT  ID
                FROM    Test
                WHERE   PlainVarcharColumn = @P1 ',N'Стоял он, дум великих полн'
    
        // Profiler (Setting DIS-abled)
        exec sp_prepexec @p1 output,N'@P1 varchar(8000)',N'SELECT  ID
                FROM    Test
                WHERE   PlainVarcharColumn = @P1 ','????? ??, ??? ??????? ????'