SQLSETPROP(con,"Transactions",2) SQLEXEC(con,"...") ... SQLEXEC(con,"...") SQLROLLBACK(con)/SQLCOMMIT(con) SQLSETPROP(con,"Transactions",1)Later in this message I will show that CursorAdapter doesn't interfere with this approach.
>lnResult = SQLEXEC(connection,"BEGIN TRANSACTION") >IF lnResult = -1 >* Error checking here and return. >ENDIF > >* At this moment I have one open transaction on the backend. Looks ok to me. > >llSuccess = TABLEUPDATE(.T.,.F.,"cursoradapter1") && as soon as this executes, transaction is gone. >IF NOT llSuccess >*Error checking here and return >ENDIF > >llSucces = TABLEUPDATE(.T.,.F.,"cursoradapter2") && this one is not in a transaction anymore. >>
>BEGIN TRASACTION (1) - started programatically > >BEGIN TRASACTION (2) - in BeforeCursorUpdate() >update >COMMIT TRAN && made automatically by the CA - can't disable that > >BEGIN TRANSACTION (2) - in BeforeCursorUpdate() >update >COMMIT TRAN && made automatically by the CA - can't disable that > >COMMIT TRANSACTION (1) - executed programatically. >>
>lnResult = SQLEXEC(connection,"BEGIN TRANSACTION") >IF lnResult = -1 >* Error checking here and return. >ENDIF > >* At this moment I have one open transaction on the backend. Looks ok to me. > >llSuccess = TABLEUPDATE(.T.,.F.,"cursoradapter1") >* Stepping on through the code, BeforeCursorUpdate fires, *then it executes the BEGIN TRANSACTION, and I have 2 open transactions. *This looks ok too. After the update, trancount is 1, and it behaves at expected. > >IF NOT llSuccess >*Error checking here and return >ENDIF > >* Not to the second CA: > >llSucces = TABLEUPDATE(.T.,.F.,"cursoradapter2") >* Stepping through the code, I see BEGIN TRANSACTION executed, *switched to Enterprise Manager, see 2 open transactions, then *follows the update. After the update BOTH TRANSACTIONS ARE GONE!!!!! >>
CLOSE DATABASES all CLEAR DELETE DATABASE TestTransaction ?VERSION() con=SQLCONNECT("LocalServer") && point to any available SQL Server IF con<1 ? "FAILED to connect!!!" RETURN ENDIF SQLEXEC(con,"SET ANSI_PADDING ON") SQLEXEC(con,"create table testtransaction1 (f1 int, f2 char(10))") SQLEXEC(con,"create table testtransaction2 (f3 int, f4 char(10))") CREATE DATABASE TestTransaction CREATE CONNECTION testcon CONNSTRING (SQLGETPROP(con,"ConnectString")) CREATE SQL VIEW testview REMOTE CONNECTION testcon AS ; select * from testtransaction1,testtransaction2 ; WHERE testtransaction1.f1=testtransaction2.f3 DBSETPROP("testview","VIEW","SendUpdates",.T.) USE testview CURSORSETPROP("Buffering",5) INSERT INTO testview values(1,"1111",1,"2222") ?[TABLEUPDATE(.T.)],TABLEUPDATE(.T.) SQLEXEC(con,"select * from testtransaction1,testtransaction2 WHERE testtransaction1.f1=testtransaction2.f3","result") SELECT result LIST CLOSE TABLES SQLEXEC(con,"DROP table testtransaction1") SQLEXEC(con,"DROP table testtransaction2") SQLDISCONNECT(0)Here is what I see in SQL Profiler:
SQL:BatchCompleted select * from testtransaction1,testtransaction2 WHERE testtransaction1.f1=testtransaction2.f3 SQL:BatchCompleted set implicit_transactions on <========= !!!! RPC:Completed exec sp_executesql N'INSERT INTO testtransaction1 (f1,f2) VALUES (@P1,@P2)', N'@P1 int,@P2 char(10)', 1, '1111 ' RPC:Completed exec sp_executesql N'INSERT INTO testtransaction2 (f3,f4) VALUES (@P1,@P2)', N'@P1 int,@P2 char(10)', 1, '2222 ' SQL:BatchCompleted IF @@TRANCOUNT > 0 COMMIT TRAN <========= !!!! SQL:BatchCompleted select * from testtransaction1,testtransaction2 WHERE testtransaction1.f1=testtransaction2.f3 Audit Logout SQL:BatchCompleted DROP table testtransaction1 SQL:BatchCompleted DROP table testtransaction2 Audit LogoutMarked lines are indication of the fact that remote view uses transaction during TABLEUPDATE. You better watch out for this scenarios in your application if you are managing transactions behind VFP back.
CLOSE DATABASES all CLEAR ?VERSION() con=SQLCONNECT("LocalServer") && point to any available SQL Server IF con<1 ? "FAILED to connect!!!" RETURN ENDIF SQLEXEC(con,"SET ANSI_PADDING ON") SQLEXEC(con,"create table #testtransaction (f1 int, f2 char(10))") SQLEXEC(con,"insert into #testtransaction values(1,'11111')") LOCAL oCA as CursorAdapter oCA=CREATEOBJECT("CursorAdapter") oCA.DataSourceType="ODBC" oCA.DataSource=con oCA.SelectCmd="select * from #testtransaction" oCA.Tables="#testtransaction" oCA.KeyFieldList="f1" oCA.UpdatableFieldList="f1, f2" oCA.UpdateNameList="f1 #testtransaction.f1, f2 #testtransaction.f2" oCA.BufferModeOverride= 5 oCA.UpdateType= 2 oCA.CursorFill() ? "----------USE automatic commit------------" ? SELECT (oCA.Alias) LIST SQLSETPROP(con,"Transactions",1) SQLEXEC(con,"select @@TRANCOUNT as count", "trancount") ? "Current trancount:",trancount.count UPDATE (oCA.Alias) SET f2=RTRIM(f2)+"2" SELECT (oCA.Alias) ?[SQLGETPROP(con,"Transactions")=],SQLGETPROP(con,"Transactions") ?"TABLEUPDATE(.T.):",TABLEUPDATE(.T.) ?[SQLGETPROP(con,"Transactions")=],SQLGETPROP(con,"Transactions") SQLEXEC(con,"select @@TRANCOUNT as count", "trancount") ? "Current trancount:",trancount.count SQLEXEC(con,"select * from #testtransaction","currentstate") SELECT currentstate LIST ? "----------Done with automatic commit------------" ? ? "----------USE manual commit------------" ? SQLSETPROP(con,"Transactions",2) SQLEXEC(con,"select * from #testtransaction","currentstate") SELECT currentstate LIST SQLEXEC(con,"select @@TRANCOUNT as count", "trancount") ? "Current trancount:",trancount.count UPDATE (oCA.Alias) SET f2=RTRIM(f2)+"3" SELECT (oCA.Alias) ?[SQLGETPROP(con,"Transactions")=],SQLGETPROP(con,"Transactions") ?"TABLEUPDATE(.T.):",TABLEUPDATE(.T.) ?[SQLGETPROP(con,"Transactions")=],SQLGETPROP(con,"Transactions") SQLEXEC(con,"select @@TRANCOUNT as count", "trancount") ? "Current trancount:",trancount.count SQLEXEC(con,"select * from #testtransaction","currentstate") SELECT currentstate LIST ? "Rollback Transaction:",SQLROLLBACK(con) SQLEXEC(con,"select @@TRANCOUNT as count", "trancount") ? "Current trancount:",trancount.count SQLEXEC(con,"select * from #testtransaction","currentstate") SELECT currentstate LIST SQLSETPROP(con,"Transactions",1) ?[SQLGETPROP(con,"Transactions")=],SQLGETPROP(con,"Transactions") ? "----------Done with manual commit------------" ? ? "----------Try T-SQL BEGIN TRANSACTION------------" SQLEXEC(con,"BEGIN TRANSACTION") SQLEXEC(con,"select @@TRANCOUNT as count", "trancount") ? "Current trancount:",trancount.count ?[SQLGETPROP(con,"Transactions")=],SQLGETPROP(con,"Transactions") SQLEXEC(con,"COMMIT TRANSACTION") ? "----------Done with T-SQL BEGIN TRANSACTION------------" USE IN (oCA.Alias) SQLDISCONNECT(con)VFP output:
Visual FoxPro 08.00.0000.2521 for Windows ----------USE automatic commit------------ Record# F1 F2 1 1 11111 Current trancount: 0 SQLGETPROP(con,"Transactions")= 1 TABLEUPDATE(.T.): .T. SQLGETPROP(con,"Transactions")= 1 Current trancount: 0 Record# F1 F2 1 1 111112 ----------Done with automatic commit------------ ----------USE manual commit------------ Record# F1 F2 1 1 111112 Current trancount: 1 SQLGETPROP(con,"Transactions")= 2 TABLEUPDATE(.T.): .T. SQLGETPROP(con,"Transactions")= 2 Current trancount: 1 Record# F1 F2 1 1 1111123 Rollback Transaction: 1 Current trancount: 0 Record# F1 F2 1 1 111112 SQLGETPROP(con,"Transactions")= 1 ----------Done with manual commit------------ ----------Try T-SQL BEGIN TRANSACTION------------ Current trancount: 1 SQLGETPROP(con,"Transactions")= 1 ----------Done with T-SQL BEGIN TRANSACTION------------Sql Profiler output:
SQL:BatchCompleted SET ANSI_PADDING ON SQL:BatchCompleted create table #testtransaction (f1 int, f2 char(10)) SQL:BatchCompleted insert into #testtransaction values(1,'11111') SQL:BatchCompleted select * from #testtransaction SQL:BatchCompleted select @@TRANCOUNT as count SQL:BatchCompleted set implicit_transactions on RPC:Completed exec sp_executesql N'DELETE FROM #testtransaction WHERE f1=@P1 AND f2=@P2 ; INSERT INTO #testtransaction (f1,f2) VALUES (@P3 ,@P4 )', N'@P1 int,@P2 varchar(10),@P3 float,@P4 varchar(10)', 1, '11111 ', 1.000000000000000e+000, '111112 ' SQL:BatchCompleted IF @@TRANCOUNT > 0 COMMIT TRAN SQL:BatchCompleted set implicit_transactions off SQL:BatchCompleted select @@TRANCOUNT as count SQL:BatchCompleted select * from #testtransaction SQL:BatchCompleted set implicit_transactions on SQL:BatchCompleted select * from #testtransaction SQL:BatchCompleted select @@TRANCOUNT as count RPC:Completed exec sp_executesql N'DELETE FROM #testtransaction WHERE f1=@P1 AND f2=@P2 ; INSERT INTO #testtransaction (f1,f2) VALUES (@P3 ,@P4 )', N'@P1 int,@P2 varchar(10), @P3 float,@P4 varchar(10)', 1, '111112 ', 1.000000000000000e+000, '1111123 ' SQL:BatchCompleted select @@TRANCOUNT as count SQL:BatchCompleted select * from #testtransaction SQL:BatchCompleted IF @@TRANCOUNT > 0 ROLLBACK TRAN SQL:BatchCompleted select @@TRANCOUNT as count SQL:BatchCompleted select * from #testtransaction SQL:BatchCompleted IF @@TRANCOUNT > 0 COMMIT TRAN SQL:BatchCompleted set implicit_transactions off SQL:BatchCompleted BEGIN TRANSACTION SQL:BatchCompleted select @@TRANCOUNT as count SQL:BatchCompleted COMMIT TRANSACTION Audit LogoutNow, you are the one you should be angry with.