Skip to content

Support default column values in BCP with ASE #685

@mmcnabb-vms

Description

@mmcnabb-vms

Background

  • Database tables in ASE and SQL Server may be defined with a DEFAULT value that can either be a constant or a built-in function such as GETDATE()
  • When inserting a row specifying a NULL value for a field which has a default value defined, two behaviours are possible:
    • insert NULL
    • insert the default value
  • MS bcp.exe and ASE bcp commandline utility both offer commandline switches to toggle these two behaviours. the switches are -k or --ignoredefaults respectively, and in both cases the default value is inserted unless that switch is given.
  • ASE dblib bcp inserts the default value if a NULL is specified.
  • In any of the above cases where the default value is to be generated, the insert should succeed even if the column is defined as non-nullable.
  • When inserting a row but a column does not have a value specified at all (either by bcp commandline utility with a format file that omits the column, or ASE DBlib bcp API and the column is not given a value), the behaviour should be the same as if a NULL value was specified to insert.
    • MSSQL does not allow omitting columns marked as NOT NULL.
    • MSSQL bcp.exe -f does not allow omitting columns at all.
    • ASE bcp -f allows omitting columns , so long as the column is either nullable or has a default value. It gives an error otherwise.

Problem

  • Using FreeTDS freebcp.exe or DBlib bcp, to ASE, the default value is never inserted, it always inserts NULL (and rejects the insert if the column was non-nullable).

Notes

  • Using FreeTDS to MSSQL:
    • the default value is correctly inserted.
    • Although freebcp.exe does not support -k; the option -hKEEP_NULLS is a viable workaround as it has the same effect as -k.
  • There are some other bugs in freebcp.exe's handling of NULLs with MSSQL, see Handling of NULL values in FreeBCP native file format with MSSQL #686
  • MSSQL's own dblib API seems to have been discontinued decades ago so I'm not testing that now -- only their commandline bcp.

Analysis

It turns out that MSSQL and ASE implement the insertion of the default value via BCP differently:

  • In MSSQL on the wire, the default behaviour is to insert the default value. This is actioned by the server; if the server receives an INSERT request with a NULL or missing field, the server will fill it in with the default value.
    • to turn it off , the insert bulk SQL statement includes the clause with(KEEP_NULLS) which tells the server to not fill in default values for this statement.
  • In ASE BCP, the server never generates the default value. Instead, the response to insert bulk includes a column property specifying the default value for that column. The client code is responsible for replacing NULL in the user's insertion request with the default value for the column.

Items to do on this ticket

  • Support -k and --ignoredefaults switches in freebcp.
  • When talking to ASE, correctly instantiate the default value when requested. This will involve adding code to the processing of the insert bulk response to store the default value; and also applying that default value to the column data of each row being inserted.
    • This should be the default behaviour (to match the functionality of ASE's own tools), but we will need to provide a way for the user to request --ignoredefaults behaviour when using DBlib bcp with ASE. For simplicilty I propose the use of bcp_options to set KEEP_NULLS , so that the same client code works with both MSSQL and ASE.

My testing for this issue was done with ASE 16.0 SP04 Evaluation, and SQL Server 2022 x64 16.0.1150.1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions