Welcome to dbFreaks.com!
FAQFAQ    SearchSearch      ProfileProfile    Private MessagesPrivate Messages   Log inLog in

BUG & test case: ODBC client hangs or gets an error when I..

 
   Database Help (Home) -> ODBC RSS
Next:  Filemaker Hangs When Creating New Database  
Author Message
Marcel_Müller

External


Since: Nov 13, 2008
Posts: 3



(Msg. 1) Posted: Thu Nov 13, 2008 12:25 pm
Post subject: BUG & test case: ODBC client hangs or gets an error when INSERT into
Archived from groups: microsoft>public>sqlserver>odbc (more info?)

Hi,

the application below runs into Error 24000 "Invalid Cursor State" after
executing the INSERT a few times.

If I change the Trigger to

CREATE TRIGGER Trigger1 ON [Tabelle1]
FOR INSERT NOT FOR REPLICATION
AS
BEGIN
INSERT INTO Tabelle2
SELECT DISTINCT Text1
FROM inserted l
LEFT JOIN Tabelle2 r ON l.Text1 = r.[Key]
WHERE r.[Key] IS NULL
END

the ODBC client hangs with 100% CPU somewhere in the ODBC stack. No
Network activity. The last command executed in the Enterprise Manager
says "dbcc inputbuffer(54)" while the client hangs.

Inserts from other sources like Query Analyzer or a native JDBC driver
work as expected in any case (at least so far).


System environment
==================
ODBC 2000.85.1132.00 <-> SQL Server 8.00.760 SP3
ODBC 2000.85.1132.00 <-> SQL Server 8.00.2039 SP4
ODBC 3.70.11.46 <-> SQL Server 8.00.2039 SP4

I did not find any differences between the three scenarios except that
the first one crashed a bit faster than the others (usually no more than
5 lines).

The application screnario is a bit more complicated than shown, but the
principal structure and the behavior is the same.

I have no quantitative numbers but it seems that a higher performance
clients and/or network connections raises the probability of this error.
This might be the explanation why the application has run successfully
for about 6 years and half a million inserts.


Marcel Müller


Table Structure
===============
CREATE TABLE [dbo].[Tabelle1] (
[text1] [varchar] (255) NOT NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Tabelle2] (
[key] [varchar] (255) NOT NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Tabelle2] WITH NOCHECK ADD
CONSTRAINT [PK_Tabelle2] PRIMARY KEY CLUSTERED
(
[key]
) ON [PRIMARY]
GO

CREATE TRIGGER Trigger1 ON [Tabelle1]
FOR INSERT NOT FOR REPLICATION
AS
IF @@ROWCOUNT = 1
BEGIN
DECLARE @key AS VARCHAR(255)
SET @key = (SELECT TOP 1 Text1 FROM inserted)
IF NOT EXISTS (SELECT * FROM Tabelle2 WHERE [Key] = @key)
INSERT INTO Tabelle2 VALUES (@key)
END
ELSE
BEGIN
INSERT INTO Tabelle2
SELECT DISTINCT Text1
FROM inserted l
LEFT JOIN Tabelle2 r ON l.Text1 = r.[Key]
WHERE r.[Key] IS NULL
END
/*
Tabelle 2 holds a fast and consistent version of SELECT DISTINCT of
Tabelle 1. Tabelle1 typically contains only some hundrets of distinct
values in the related column while the total number of lines is in the
order of 10^7 to 10^8, which makes even a stream aggregate on the index
slow.
*/
===============

Application
===============
// Test.cpp : Defines the entry point for the console application.

#include <stdio.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>

const char* sConnect =
"DRIVER={SQL SERVER};SERVER=yamato;UID=sa;PWD=***;Database=Statistik";
const char* sStmt = "INSERT INTO Tabelle1 (Text1) VALUES (?)";

// db-Handles for odbc-access (Owned by the connection thread)
HENV hEnv;
HDBC hDBC;
HSTMT hStmt;

char col1[255];
SQLINTEGER len1;


RETCODE evalSQLFunc(RETCODE result, const char* text)
{ switch (result)
{case SQL_INVALID_HANDLE:
printf("\n%s SQL Error: invalid handle.\n", text);
exit(1);
case SQL_ERROR:
UCHAR szErrMsg[4000];
UCHAR szSqlState[6];
SQLINTEGER errnr;
SQLSMALLINT errmsg;
SQLError(hEnv, hDBC, hStmt, szSqlState, &errnr, szErrMsg, sizeof
szErrMsg, &errmsg);
printf("\n%s SQLError: %.*s\nSQLState: %s\n", text, sizeof szErrMsg,
szErrMsg, szSqlState);
exit(2);
}
return result;
}

int main(int argc, char* argv[])
{
evalSQLFunc(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv),
"SQLAllocHandle(ENV...)");
evalSQLFunc(SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER), "SQLSetEnvAttr");
evalSQLFunc(SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC),
"SQLAllocHandle(DBC...)");
evalSQLFunc(SQLSetConnectAttr(hDBC, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)
1, SQL_INTEGER), "SQLSetConnectAttr(SQL_ATTR_AUTOCOMMIT...)");

SQLCHAR szOutConn[2048];
SQLSMALLINT cbOutConn;
evalSQLFunc(SQLDriverConnect(hDBC, 0, (UCHAR*)sConnect, SQL_NTS,
szOutConn, sizeof(szOutConn), &cbOutConn, SQL_DRIVER_NOPROMPT),
"SQLDriverConnect");

/* SQL INSERT-STATEMENT */
evalSQLFunc(SQLAllocHandle(SQL_HANDLE_STMT, hDBC, &hStmt),
"SQLAllocHandle(STMT...)");
evalSQLFunc(SQLPrepare(hStmt, (UCHAR*)sStmt,
(SQLINTEGER)strlen(sStmt)), "SQLPrepare");

evalSQLFunc(SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY,
SQL_VARCHAR, sizeof col1, 0, col1, 0, &len1), "SQLBindParameter(1...)");

for (int i = 0; i < 100000; ++i)
{ len1 = sprintf(col1, "Test %i\n", i);
evalSQLFunc(SQLExecute(hStmt), "SQLExecute");
printf("\r%s", col1);
}

return 0;
}

 >> Stay informed about: BUG & test case: ODBC client hangs or gets an error when I.. 
Back to top
Login to vote
Sylvain Lafontaine1

External


Since: Dec 13, 2003
Posts: 301



(Msg. 2) Posted: Sat Nov 15, 2008 4:16 pm
Post subject: Re: BUG & test case: ODBC client hangs or gets an error when INSERT into a table with a Trigger [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

Having pleasure using this old stuff?

In your case, maybe you have some sort of concurrency problem: the
SQL-Server has yet to finish the previous insert when the next arrives. I
would think that this is impossible because you are using a single
connection but with this old stuff, we never know. If I were you, I would
use the serializable isolation level to make the insert. For example, in
the case where @@row = 1:

...
IF NOT EXISTS (SELECT * FROM Tabelle2 with (Updlock, Holdlock)
WHERE [Key] = @key)
INSERT INTO Tabelle2 VALUES (@key)
...

Also, your design looks curious and not well normalized. If the values for
@key are the same between Tabelle1 and Tabelle2, then you should store it
only on Tabelle2 and use a foreign key relationship between Tabelle1 and
Tabelle2 using the primary key of Tabelle2. After that, you use a stored
procedure to check the value of the key against Tabelle2 and insert it if
it's not already there and only after that, make the insertion into
Tabelle1.

Using Triggers might looks funny but this can lead you to a lot of trouble.
For example, with this design, the value of @@identity is changed inside the
trigger when you perform an insertion on Tabelle1. Some stuff - for example
using an ODBC linked table inside Access - will choke on this.

Also, if I were you, I would use ADO and an OLEDB provider instead of this
sql.h stuff; see for example:

http://www.codersource.net/mfc_ado_insert.html
http://www.codersource.net/c++_ado_stored_procedure.html
http://msdn.microsoft.com/en-us/library/aa905885(SQL.80).aspx

Probably that a lot of people will tell you that using ODBC will give you a
faster code because it is older (and simpler) but when your code chokes and
stop, there is nothing faster in it.

--
Sylvain Lafontaine, ing.
MVP - Technologies Virtual-PC
E-mail: sylvain aei ca (fill the blanks, no spam please)


"Marcel Müller" wrote in message

> Hi,
>
> the application below runs into Error 24000 "Invalid Cursor State" after
> executing the INSERT a few times.
>
> If I change the Trigger to
>
> CREATE TRIGGER Trigger1 ON [Tabelle1]
> FOR INSERT NOT FOR REPLICATION
> AS
> BEGIN
> INSERT INTO Tabelle2
> SELECT DISTINCT Text1
> FROM inserted l
> LEFT JOIN Tabelle2 r ON l.Text1 = r.[Key]
> WHERE r.[Key] IS NULL
> END
>
> the ODBC client hangs with 100% CPU somewhere in the ODBC stack. No
> Network activity. The last command executed in the Enterprise Manager says
> "dbcc inputbuffer(54)" while the client hangs.
>
> Inserts from other sources like Query Analyzer or a native JDBC driver
> work as expected in any case (at least so far).
>
>
> System environment
> ==================
> ODBC 2000.85.1132.00 <-> SQL Server 8.00.760 SP3
> ODBC 2000.85.1132.00 <-> SQL Server 8.00.2039 SP4
> ODBC 3.70.11.46 <-> SQL Server 8.00.2039 SP4
>
> I did not find any differences between the three scenarios except that the
> first one crashed a bit faster than the others (usually no more than 5
> lines).
>
> The application screnario is a bit more complicated than shown, but the
> principal structure and the behavior is the same.
>
> I have no quantitative numbers but it seems that a higher performance
> clients and/or network connections raises the probability of this error.
> This might be the explanation why the application has run successfully for
> about 6 years and half a million inserts.
>
>
> Marcel Müller
>
>
> Table Structure
> ===============
> CREATE TABLE [dbo].[Tabelle1] (
> [text1] [varchar] (255) NOT NULL
> ) ON [PRIMARY]
> GO
>
> CREATE TABLE [dbo].[Tabelle2] (
> [key] [varchar] (255) NOT NULL
> ) ON [PRIMARY]
> GO
>
> ALTER TABLE [dbo].[Tabelle2] WITH NOCHECK ADD
> CONSTRAINT [PK_Tabelle2] PRIMARY KEY CLUSTERED
> (
> [key]
> ) ON [PRIMARY]
> GO
>
> CREATE TRIGGER Trigger1 ON [Tabelle1]
> FOR INSERT NOT FOR REPLICATION
> AS
> IF @@ROWCOUNT = 1
> BEGIN
> DECLARE @key AS VARCHAR(255)
> SET @key = (SELECT TOP 1 Text1 FROM inserted)
> IF NOT EXISTS (SELECT * FROM Tabelle2 WHERE [Key] = @key)
> INSERT INTO Tabelle2 VALUES (@key)
> END
> ELSE
> BEGIN
> INSERT INTO Tabelle2
> SELECT DISTINCT Text1
> FROM inserted l
> LEFT JOIN Tabelle2 r ON l.Text1 = r.[Key]
> WHERE r.[Key] IS NULL
> END
> /*
> Tabelle 2 holds a fast and consistent version of SELECT DISTINCT of
> Tabelle 1. Tabelle1 typically contains only some hundrets of distinct
> values in the related column while the total number of lines is in the
> order of 10^7 to 10^8, which makes even a stream aggregate on the index
> slow.
> */
> ===============
>
> Application
> ===============
> // Test.cpp : Defines the entry point for the console application.
>
> #include <stdio.h>
> #include <windows.h>
> #include <sql.h>
> #include <sqlext.h>
>
> const char* sConnect =
> "DRIVER={SQL SERVER};SERVER=yamato;UID=sa;PWD=***;Database=Statistik";
> const char* sStmt = "INSERT INTO Tabelle1 (Text1) VALUES (?)";
>
> // db-Handles for odbc-access (Owned by the connection thread)
> HENV hEnv;
> HDBC hDBC;
> HSTMT hStmt;
>
> char col1[255];
> SQLINTEGER len1;
>
>
> RETCODE evalSQLFunc(RETCODE result, const char* text)
> { switch (result)
> {case SQL_INVALID_HANDLE:
> printf("\n%s SQL Error: invalid handle.\n", text);
> exit(1);
> case SQL_ERROR:
> UCHAR szErrMsg[4000];
> UCHAR szSqlState[6];
> SQLINTEGER errnr;
> SQLSMALLINT errmsg;
> SQLError(hEnv, hDBC, hStmt, szSqlState, &errnr, szErrMsg, sizeof szErrMsg,
> &errmsg);
> printf("\n%s SQLError: %.*s\nSQLState: %s\n", text, sizeof szErrMsg,
> szErrMsg, szSqlState);
> exit(2);
> }
> return result;
> }
>
> int main(int argc, char* argv[])
> {
> evalSQLFunc(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv),
> "SQLAllocHandle(ENV...)");
> evalSQLFunc(SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION,
> (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER), "SQLSetEnvAttr");
> evalSQLFunc(SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC),
> "SQLAllocHandle(DBC...)");
> evalSQLFunc(SQLSetConnectAttr(hDBC, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) 1,
> SQL_INTEGER), "SQLSetConnectAttr(SQL_ATTR_AUTOCOMMIT...)");
>
> SQLCHAR szOutConn[2048];
> SQLSMALLINT cbOutConn;
> evalSQLFunc(SQLDriverConnect(hDBC, 0, (UCHAR*)sConnect, SQL_NTS,
> szOutConn, sizeof(szOutConn), &cbOutConn, SQL_DRIVER_NOPROMPT),
> "SQLDriverConnect");
>
> /* SQL INSERT-STATEMENT */
> evalSQLFunc(SQLAllocHandle(SQL_HANDLE_STMT, hDBC, &hStmt),
> "SQLAllocHandle(STMT...)");
> evalSQLFunc(SQLPrepare(hStmt, (UCHAR*)sStmt, (SQLINTEGER)strlen(sStmt)),
> "SQLPrepare");
>
> evalSQLFunc(SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY,
> SQL_VARCHAR, sizeof col1, 0, col1, 0, &len1), "SQLBindParameter(1...)");
>
> for (int i = 0; i < 100000; ++i)
> { len1 = sprintf(col1, "Test %i\n", i);
> evalSQLFunc(SQLExecute(hStmt), "SQLExecute");
> printf("\r%s", col1);
> }
>
> return 0;
> }

 >> Stay informed about: BUG & test case: ODBC client hangs or gets an error when I.. 
Back to top
Login to vote
Sylvain Lafontaine1

External


Since: Dec 13, 2003
Posts: 301



(Msg. 3) Posted: Sun Nov 16, 2008 11:50 pm
Post subject: Re: BUG & test case: ODBC client hangs or gets an error when INSERT into a table with a Trigger [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

Also, I should have added that maybe you could find setting IGNORE_DUP_KEY =
ON for the primary key of Tabelle2 useful instead of checking for the
possibility of a duplicate in your trigger.

--
Sylvain Lafontaine, ing.
MVP - Technologies Virtual-PC
E-mail: sylvain aei ca (fill the blanks, no spam please)


"Sylvain Lafontaine" <sylvain aei ca (fill the blanks, no spam please)>
wrote in message
> Having pleasure using this old stuff?
>
> In your case, maybe you have some sort of concurrency problem: the
> SQL-Server has yet to finish the previous insert when the next arrives. I
> would think that this is impossible because you are using a single
> connection but with this old stuff, we never know. If I were you, I would
> use the serializable isolation level to make the insert. For example, in
> the case where @@row = 1:
>
> ...
> IF NOT EXISTS (SELECT * FROM Tabelle2 with (Updlock, Holdlock)
> WHERE [Key] = @key)
> INSERT INTO Tabelle2 VALUES (@key)
> ...
>
> Also, your design looks curious and not well normalized. If the values
> for @key are the same between Tabelle1 and Tabelle2, then you should store
> it only on Tabelle2 and use a foreign key relationship between Tabelle1
> and Tabelle2 using the primary key of Tabelle2. After that, you use a
> stored procedure to check the value of the key against Tabelle2 and insert
> it if it's not already there and only after that, make the insertion into
> Tabelle1.
>
> Using Triggers might looks funny but this can lead you to a lot of
> trouble. For example, with this design, the value of @@identity is changed
> inside the trigger when you perform an insertion on Tabelle1. Some
> stuff - for example using an ODBC linked table inside Access - will choke
> on this.
>
> Also, if I were you, I would use ADO and an OLEDB provider instead of this
> sql.h stuff; see for example:
>
> http://www.codersource.net/mfc_ado_insert.html
> http://www.codersource.net/c++_ado_stored_procedure.html
> http://msdn.microsoft.com/en-us/library/aa905885(SQL.80).aspx
>
> Probably that a lot of people will tell you that using ODBC will give you
> a faster code because it is older (and simpler) but when your code chokes
> and stop, there is nothing faster in it.
>
> --
> Sylvain Lafontaine, ing.
> MVP - Technologies Virtual-PC
> E-mail: sylvain aei ca (fill the blanks, no spam please)
>
>
> "Marcel Müller" wrote in message
>
>> Hi,
>>
>> the application below runs into Error 24000 "Invalid Cursor State" after
>> executing the INSERT a few times.
>>
>> If I change the Trigger to
>>
>> CREATE TRIGGER Trigger1 ON [Tabelle1]
>> FOR INSERT NOT FOR REPLICATION
>> AS
>> BEGIN
>> INSERT INTO Tabelle2
>> SELECT DISTINCT Text1
>> FROM inserted l
>> LEFT JOIN Tabelle2 r ON l.Text1 = r.[Key]
>> WHERE r.[Key] IS NULL
>> END
>>
>> the ODBC client hangs with 100% CPU somewhere in the ODBC stack. No
>> Network activity. The last command executed in the Enterprise Manager
>> says "dbcc inputbuffer(54)" while the client hangs.
>>
>> Inserts from other sources like Query Analyzer or a native JDBC driver
>> work as expected in any case (at least so far).
>>
>>
>> System environment
>> ==================
>> ODBC 2000.85.1132.00 <-> SQL Server 8.00.760 SP3
>> ODBC 2000.85.1132.00 <-> SQL Server 8.00.2039 SP4
>> ODBC 3.70.11.46 <-> SQL Server 8.00.2039 SP4
>>
>> I did not find any differences between the three scenarios except that
>> the first one crashed a bit faster than the others (usually no more than
>> 5 lines).
>>
>> The application screnario is a bit more complicated than shown, but the
>> principal structure and the behavior is the same.
>>
>> I have no quantitative numbers but it seems that a higher performance
>> clients and/or network connections raises the probability of this error.
>> This might be the explanation why the application has run successfully
>> for about 6 years and half a million inserts.
>>
>>
>> Marcel Müller
>>
>>
>> Table Structure
>> ===============
>> CREATE TABLE [dbo].[Tabelle1] (
>> [text1] [varchar] (255) NOT NULL
>> ) ON [PRIMARY]
>> GO
>>
>> CREATE TABLE [dbo].[Tabelle2] (
>> [key] [varchar] (255) NOT NULL
>> ) ON [PRIMARY]
>> GO
>>
>> ALTER TABLE [dbo].[Tabelle2] WITH NOCHECK ADD
>> CONSTRAINT [PK_Tabelle2] PRIMARY KEY CLUSTERED
>> (
>> [key]
>> ) ON [PRIMARY]
>> GO
>>
>> CREATE TRIGGER Trigger1 ON [Tabelle1]
>> FOR INSERT NOT FOR REPLICATION
>> AS
>> IF @@ROWCOUNT = 1
>> BEGIN
>> DECLARE @key AS VARCHAR(255)
>> SET @key = (SELECT TOP 1 Text1 FROM inserted)
>> IF NOT EXISTS (SELECT * FROM Tabelle2 WHERE [Key] = @key)
>> INSERT INTO Tabelle2 VALUES (@key)
>> END
>> ELSE
>> BEGIN
>> INSERT INTO Tabelle2
>> SELECT DISTINCT Text1
>> FROM inserted l
>> LEFT JOIN Tabelle2 r ON l.Text1 = r.[Key]
>> WHERE r.[Key] IS NULL
>> END
>> /*
>> Tabelle 2 holds a fast and consistent version of SELECT DISTINCT of
>> Tabelle 1. Tabelle1 typically contains only some hundrets of distinct
>> values in the related column while the total number of lines is in the
>> order of 10^7 to 10^8, which makes even a stream aggregate on the index
>> slow.
>> */
>> ===============
>>
>> Application
>> ===============
>> // Test.cpp : Defines the entry point for the console application.
>>
>> #include <stdio.h>
>> #include <windows.h>
>> #include <sql.h>
>> #include <sqlext.h>
>>
>> const char* sConnect =
>> "DRIVER={SQL SERVER};SERVER=yamato;UID=sa;PWD=***;Database=Statistik";
>> const char* sStmt = "INSERT INTO Tabelle1 (Text1) VALUES (?)";
>>
>> // db-Handles for odbc-access (Owned by the connection thread)
>> HENV hEnv;
>> HDBC hDBC;
>> HSTMT hStmt;
>>
>> char col1[255];
>> SQLINTEGER len1;
>>
>>
>> RETCODE evalSQLFunc(RETCODE result, const char* text)
>> { switch (result)
>> {case SQL_INVALID_HANDLE:
>> printf("\n%s SQL Error: invalid handle.\n", text);
>> exit(1);
>> case SQL_ERROR:
>> UCHAR szErrMsg[4000];
>> UCHAR szSqlState[6];
>> SQLINTEGER errnr;
>> SQLSMALLINT errmsg;
>> SQLError(hEnv, hDBC, hStmt, szSqlState, &errnr, szErrMsg, sizeof
>> szErrMsg, &errmsg);
>> printf("\n%s SQLError: %.*s\nSQLState: %s\n", text, sizeof szErrMsg,
>> szErrMsg, szSqlState);
>> exit(2);
>> }
>> return result;
>> }
>>
>> int main(int argc, char* argv[])
>> {
>> evalSQLFunc(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv),
>> "SQLAllocHandle(ENV...)");
>> evalSQLFunc(SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION,
>> (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER), "SQLSetEnvAttr");
>> evalSQLFunc(SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC),
>> "SQLAllocHandle(DBC...)");
>> evalSQLFunc(SQLSetConnectAttr(hDBC, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) 1,
>> SQL_INTEGER), "SQLSetConnectAttr(SQL_ATTR_AUTOCOMMIT...)");
>>
>> SQLCHAR szOutConn[2048];
>> SQLSMALLINT cbOutConn;
>> evalSQLFunc(SQLDriverConnect(hDBC, 0, (UCHAR*)sConnect, SQL_NTS,
>> szOutConn, sizeof(szOutConn), &cbOutConn, SQL_DRIVER_NOPROMPT),
>> "SQLDriverConnect");
>>
>> /* SQL INSERT-STATEMENT */
>> evalSQLFunc(SQLAllocHandle(SQL_HANDLE_STMT, hDBC, &hStmt),
>> "SQLAllocHandle(STMT...)");
>> evalSQLFunc(SQLPrepare(hStmt, (UCHAR*)sStmt, (SQLINTEGER)strlen(sStmt)),
>> "SQLPrepare");
>>
>> evalSQLFunc(SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY,
>> SQL_VARCHAR, sizeof col1, 0, col1, 0, &len1), "SQLBindParameter(1...)");
>>
>> for (int i = 0; i < 100000; ++i)
>> { len1 = sprintf(col1, "Test %i\n", i);
>> evalSQLFunc(SQLExecute(hStmt), "SQLExecute");
>> printf("\r%s", col1);
>> }
>>
>> return 0;
>> }
>
>
 >> Stay informed about: BUG & test case: ODBC client hangs or gets an error when I.. 
Back to top
Login to vote
Marcel_Müller

External


Since: Nov 13, 2008
Posts: 3



(Msg. 4) Posted: Mon Nov 17, 2008 1:25 pm
Post subject: Re: BUG & test case: ODBC client hangs or gets an error when INSERT [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

Sylvain Lafontaine schrieb:
> Having pleasure using this old stuff?

Not really...

> In your case, maybe you have some sort of concurrency problem: the
> SQL-Server has yet to finish the previous insert when the next arrives. I
> would think that this is impossible because you are using a single
> connection but with this old stuff, we never know. If I were you, I would
> use the serializable isolation level to make the insert. For example, in
> the case where @@row = 1:
>
> ...
> IF NOT EXISTS (SELECT * FROM Tabelle2 with (Updlock, Holdlock)
> WHERE [Key] = @key)
> INSERT INTO Tabelle2 VALUES (@key)

You are right. The example code could end with a duplicate key error,
because the IF NOT EXISTS is non-atomic with the insert. In fact that
never happened. The probability of the IF clause to become true is about
1:100,000. The probability of two adjacent lines to cause an insert is
even lower.

Furthermore, the test application still fails with the same errors if I
set the transaction isolation level to serializable. I forgot to mention
this.


> Also, your design looks curious and not well normalized. If the values for
> @key are the same between Tabelle1 and Tabelle2, then you should store it
> only on Tabelle2 and use a foreign key relationship between Tabelle1 and
> Tabelle2 using the primary key of Tabelle2.

This would effectivly result in a foreign key error when inserting into
Tabelle1 without generating the matching lines in Tabelle2 before.

From the application's point of view Tabelle2 is nothing but a cache to
Tabelle1. From the data model it does not exist at all. It is only a
fast way to replace the slow SELECT DISTINCT which always requierd a
full index scan on the secondary index of the key column in Tabelle1.


> After that, you use a stored
> procedure to check the value of the key against Tabelle2 and insert it if
> it's not already there and only after that, make the insertion into
> Tabelle1.

Of course, a strored procedure would be a work-around. Unfortunately
Tabelle1 is part of a very basic API interface (public insert allowed).
So a bunch of applications have to be touched to replace the INSERTs by
the procedure call. So I do not have this option.

I should mention that it is essential to the application, that Tabelle1
contains no keys that are not in Tabelle2. The other way around is non
critical. The foreign key would check for this, but the inserting
applications cannot deal with the resulting errors. So this won't help
at all. Updates on Tabelle1 or Tabelle2 are not permitted anyway.


> Using Triggers might looks funny but this can lead you to a lot of trouble.

6 years of this design went by without trouble. Last year I got the
error once. Now I get it every few milliseconds. The code and the
binaries are unchanged for years. The most recent change is the service
pack of the SQL server, but only at one machine. The other one fails too.

> For example, with this design, the value of @@identity is changed inside the
> trigger when you perform an insertion on Tabelle1. Some stuff - for example
> using an ODBC linked table inside Access - will choke on this.

No one use Access for a table with 40 million lines.
And I am sure that inserting lines into Tabelle1 without an insert into
Tabelle2 even once is sufficient to trigger the error.

> Also, if I were you, I would use ADO and an OLEDB provider instead of this
> sql.h stuff; see for example:

Which in fact means to rewrite the entire DB interface.
If nothing helps, this might be the way.


> Probably that a lot of people will tell you that using ODBC will give you a
> faster code because it is older (and simpler) but when your code chokes and
> stop, there is nothing faster in it.

Already tested with another application. ODBC is definitely faster.
However, Speed is not the primary issue in this case.


Marcel
 >> Stay informed about: BUG & test case: ODBC client hangs or gets an error when I.. 
Back to top
Login to vote
Marcel_Müller

External


Since: Nov 13, 2008
Posts: 3



(Msg. 5) Posted: Mon Nov 17, 2008 1:25 pm
Post subject: Re: BUG & test case: ODBC client hangs or gets an error when INSERT [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

Sylvain Lafontaine schrieb:
> Also, I should have added that maybe you could find setting IGNORE_DUP_KEY =
> ON for the primary key of Tabelle2 useful instead of checking for the
> possibility of a duplicate in your trigger.

The option is not available for primary keys.
But I just tested with a unique clustered index with IGNORE_DUP_KEY and

CREATE TRIGGER Trigger1 ON [Tabelle1]
FOR INSERT NOT FOR REPLICATION
AS
BEGIN
INSERT INTO Tabelle2 SELECT DISTINCT Text1 FROM inserted
END

-> client hangs in an infinite loop in sqlsrv32.dll.


Marcel
 >> Stay informed about: BUG & test case: ODBC client hangs or gets an error when I.. 
Back to top
Login to vote
Display posts from previous:   
Related Topics:
odbc connection hangs jobs on one server but not another - I have two sql servers and one aix/unix server. server 1 - windows 2003 r3 running Microsoft SQL Server 2000 - 8.00.760 build 3790 server 2 - windows 2000 sp 4 running Microsoft SQL Server 2000 - 8.00.760 build 3790 server 3 - aix - unix running a...

SQL Native Client / ODBC connection - When I try to connect to my SQL Server Express using an ODBC connection (from the ODBC Control Panel in Windows XP SP2 Administrative Tools) clicking on the drop down list of servers times out with no servers listed. I can connect to the SQL server..

ODBC error with windows 95 - Good mortning to all first i'm sory for my bad english .. i've thi problem, i've to connet one clinet with Windows 95 by ODBC to an SQL server 2000. Always if i use tpc/ip or and login like sa or windows authentication the error is the same: Unable to..

SQL Native Client throws up error while dealing with ## te.. - I have created a system DSN Using SQL Server 2005 - SQL Native Client to connect to a database with compatibility set to 80. While I was creating index on the global temporary table I get the following error. ----------------------------------------..

Connection Error using SQL Server ODBC - Hi, I'm trying to connect to an SQL Server using an ODBC driver, typed in the Machine name, but it won't let me connect. Where the wizard asks me what the server name is that I want to connect to, the drop down is empty. I thought it should show me...
   Database Help (Home) -> ODBC All times are: Pacific Time (US & Canada)
Page 1 of 1

 
You can post new topics in this forum
You can reply to topics in this forum
You can edit your posts in this forum
You can delete your posts in this forum
You can vote in polls in this forum



[ Contact us | Terms of Service/Privacy Policy ]