views:

682

answers:

6

I'm experiencing something a bit strange.

I have a table on SQL Server 2008, say StockEvent that contains a Description field defined as nVarchar(MAX).
The field is set to be Nullable, has no default value and no index on it.

That table is linked into an Access 2007 application, but if I explicitly insert a NULL into the field, I'm systematically getting:

Run-time Error '3155' ODBC--insert on a linked table 'StockEvent' failed.

So the following bits of code in Access both reproduce the error:

Public Sub testinsertDAO()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Set db = CurrentDb
    Set rs = db.OpenRecordset("StockEvent", _
                              dbOpenDynaset, _
                              dbSeeChanges + dbFailOnError)
    rs.AddNew
    rs!Description = Null
    rs.Update
    rs.Close
    Set rs = Nothing
    Set db = Nothing
End Sub

Public Sub testinsertSQL()
    Dim db As DAO.Database
    Set db = CurrentDb
    db.Execute "INSERT INTO StockEvent (Description) VALUES (NULL);", _
               dbSeeChanges
    Set db = Nothing
End Sub

However, if I do the same thing from the SQL Server Management Studio, I get no error and the record is correctly inserted:

INSERT INTO StockEvent (Description) VALUES (NULL);

It doesn't appear to be machine-specific: I tried on 3 different SQL Server installations and 2 different PCs and the results are consistent.
I initially though that the problem may be in my Access application somewhere, but I isolated the code above into its own Access database, with that unique table linked to it and the results are consistent.

So, is there some known issue with Access, or ODBC and inserting NULL values to nvarchar fields?

Update.
Thanks for the answers so far.
Still no luck understanding why though ;-(

I tried with an even smaller set of assumptions: I created a new database in SQL Server with a single table StockEvent defined as such:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[StockEvent](
 [ID] [int] IDENTITY(1,1) NOT NULL,
 [Description] [nvarchar](max) NULL
) ON [PRIMARY]

GO

Then linked that table though ODBC into the test Access 2007 application.
That application contains no forms, nothing except the exact 2 subroutines above.

  • If I click on the linked table, I can edit data and add new records in datasheet mode.
    Works fine.
  • If I try any of the 2 subs to insert a record, they fail with the 3155 error message.
    (The table is closed and not referenced anywhere else and the edit datasheet is closed.)
  • If I try the SQL insert query in SQL Server Management Studio, it works fine.

Now for the interesting bit:

  • It seems that anything as big or bigger than nvarchar(256), including nvarchar(MAX) will fail.
  • Anything with on or below nvarchar(255) works.
    It's like Access was considering nvarchar as a simple string and not a memo if its size is larger than 255.
  • Even stranger, is that varchar(MAX) (wihout the n) actually works!

What I find annoying is that Microsoft's own converter from Access to SQL Server 2008 converts Memo fields into nvarchar(MAX), so I would expect this to work.

The problem now is that I need nvarchar as I'm dealing with Unicode...

+1  A: 

That should be legal syntax. Is it possible that the field you are try to give a null value is linked to other fields that don't allow null values?

Oorang
All other fields in the table allow Null, apart from the Identity field used as primary key.What I don't get is that if the case was related to the table definition, then it wouldn't work in the SQL Server management studio console either.
Renaud Bompuis
Yah, I'm just spitballing here:) This one is off the wall but you can change some of the properties of linked tables, and required is one of them. If you drop into design view on the linked table is "required" set to "Yes" by any chance? I'd also check the linked and the source table to make sure no validation rules are being violated.
Oorang
+1  A: 

Potential concurrency problem... Is the record open by another instance of Access on the same or a different machine, or does a form bound to the table have the record open in the same instance of Access on the same machine?

Renaud, try putting something in one of the other fields when you do the insert.

Also, try inserting an empty string ("") instead of a null.

Robert Harvey
No. I extracted the code you see in the question and that's the only thing in the Access application, no forms, no other table trying to access the data, no concurrency issue.
Renaud Bompuis
OK. I updated my answer.
Robert Harvey
+1  A: 

Renaud,

Did you try running a SQL Profiler trace? If you look at the Errors and Warnings category it should kick out an error if your insert failed as a result of a SQL Server constraint.

If you don't see any errors, you can safely assume that the problem is in your application.

Also, are you sure you're actually connected to SQL Server? Is CurrentDB not the same variable you're using in your Access test loop?

Aaron Alton
Hi Aaron.The update doesn't even reach the profiler, so it's clearly an ODBC or Access issue, just before the data is sent.I have updated my investigation results above.
Renaud Bompuis
+2  A: 

OK, I may have found a related answer: Ms Access linking table with nvarchar(max).

I tried using the standard SQL Server driver instead of the SQL Server Native Client driver and nvarchar(MAX) works as expected with that older driver.

It really annoys me that this seems to be a long-standing, unfixed, bug.
There is no valid reason why nvarchar should be erroneously interpreted as a string by one driver and as a memo when using another.
In both cases, they appear as memo when looking a the datatype under the table design view in Access.

If someone has any more information, please leave it on this page. I'm sure others will be glad to find it.

Renaud Bompuis
Thanks for posting the answer. I can definitely see that as a gotcha:)
Oorang
A: 

Hi, i got something similar. Please let me post here the link to my question: http://stackoverflow.com/questions/1686431/varcharmax-datatype-odbc-mapping-to-ms-access2003 I refreshed the ODBC-Links one logged on the SQL-Server 2008 itself and once from a clinet windows2003 64-bit Citrix-server getting different datatype-mappings.

The first try was perfect varchar(max) is mapped to ms-access datatype 'memo'.

The second try was poor mapping varchar(max) to ms-access datatype 'text(255)'. AND don't forget, that i am using the hole connectivity-tools from SQL2008-Server and therefore the ODBC-driver called 'SQL Native Client 10.0'. Also SSMS is installed in the Citrix.

In both cases i'm dealing with MS-access2007 and an mdb-file. I couldn't find any reason for this different behaviour - there must be a difference, but where?

Ice
A: 

Hi, it's me again.

i got annother issue (here my post: link text

In some very rare cases an error arises when saving a row with a changed memo field - same construct explained in my former post but driving sql2000-servers and it's appropriate odbc-driver (SQL SERVER).

The only weired fix is: to expand the table structure on sql-server with a column of datatype [timestamp] and refresh the odbc-links. That works and releases the show-stopper in this column on this one row ...

Maybe this info can help someone - for me it's history in going further to odbc with sql2008 in changing the datatypes [text] to [varchar(max)].

Ice