[pgsql-jp: 29021] VBA+ODBCでトランザクションを行うには

Hiroshi Saito saito @ inetrt.skcapi.co.jp
2003年 2月 12日 (水) 22:13:50 JST


さいとうです。

脱線したのでsubject:を付け替えました。
表題にそってsampleも直してまた載せました。(関係ない人ごめんなさい)

> 井上です。
>
> Hiroshi Saito wrote:
> >
> > さいとうです。
> >
> > 言われる前にテストサンプルです。(^_^;)
> >
> > > VBA+ODBCでもトランザクションの処理はできます。
> > > いろいろやり方はあるかと思いますが、問題なく使えている方法として
> > > ダイレクトSQLで処理できています。
> > > たとえVBAで待たせていてもきちんとトランザクションとして動作します。
> > > (デッドロックもちゃんとします(^_^;))
>
> ODBCを使用する場合の正しい?トランザクションへの移行処理は
>
>   SQLSetConnectOption(.., SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
>
> の発行です。この後のqueryはすべてトランザクション内で実行
> されます。トランザクションを終了するには
>
>   SQLTransact(.., .., SQL_COMMIT/SQL_ROLLBACK);
>
> を発行します。その後のqueryはまた新しいトランザクション内で
> 処理されます。トランザクション内処理を回避するには
>
>   SQLSetConnectOption(.., SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
>
> を発行する必要があります。
>
> ODBCドライバへのBEGIN/ENDの発行はおすすめできません。
> 私にはBEGINが発行された後AUTOCOMMITモードの取り扱いを
> どうすべきなのかわかりません。今の所、BEGINの発行に
> よってAUTOCOMMITモードを変更はしないので、ドライバが
> 思わぬ所でCOMMITを自動発行する可能性があると思います。

御意。m(__)m
素直に訂正。(^_^;)
このサンプルで問題なく(?)動作しています。
※忙しい井上さんにまた負担をかけてしまいました。

<動作確認>
サーバーは、PowerGres1.0β1(PostgreSQL7.3.1)
ODBC は、psqlodbc07-02-0005
Windows2000
Office97(ごめんなさい古くて)

psqlで確認
※VBAでINSERT後(--ここはトランザクションではない。
saito=> select * from saito;
  xxx
-------
 SAITO
(1 row)
※ここはVBAで待たせています。
saito=> update saito set xxx = '更新したよ' where xxx = 'SAITO';
※ここで対象がロックされているので終わるまで帰ってきません。
UPDATE 0
※ここはVBAトランザクションの終了で結局更新できなかったことを
意味しています。
saito=> select * from saito;
  xxx
--------
 したよ
(1 row)


ここからVBA--------------------------------------------------------------
'
' interfaces odbc32.dll api
'
Public Const SQL_NTS = -3
Public Const SQL_HANDLE_ENV = 1&
Public Const SQL_HANDLE_DBC = 2&
Public Const SQL_HANDLE_STMT = 3&
Public Const SQL_COMMIT = 0&
Public Const SQL_AUTOCOMMIT = 102&
Public Const SQL_AUTOCOMMIT_OFF = 0&
Public Const SQL_AUTOCOMMIT_ON = 1&

Public Declare Function _
SQLAllocHandle Lib "odbc32.dll" _
    (ByVal handletype As Integer, _
     ByVal inputhandle As Long, _
     ByRef outputhandle As Long) As Integer

Public Declare Function _
SQLAllocEnv Lib "odbc32.dll" _
    (ByRef handle As Long) As Integer

Public Declare Function _
SQLFreeHandle Lib "odbc32.dll" _
    (ByVal handletype As Integer, _
    ByVal handle As Long) As Integer

Public Declare Function _
SQLConnect Lib "odbc32.dll" _
    (ByVal hDBc As Long, _
    ByVal servername As String, _
    ByVal serverlen As Integer, _
    ByVal username As String, _
    ByVal userlen As Integer, _
    ByVal pwd As String, _
    ByVal pwdlen As Integer) As Integer

Public Declare Function _
SQLDisconnect Lib "odbc32.dll" _
    (ByVal hDBc As Long) As Integer

Public Declare Function _
SQLExecDirect Lib "odbc32.dll" _
    (ByVal hstmt As Long, _
    ByVal stmt As String, _
    ByVal stmtlen As Long) As Integer

Public Declare Function _
SQLSetConnectOption Lib "odbc32.dll" _
    (ByVal hDBc As Long, ByVal fOption As Integer, _
    ByVal vParam As Long) As Integer

Public Declare Function _
SQLTransact Lib "odbc32.dll" _
    (ByVal hEnv As Long, ByVal hDBc As Long, _
    ByVal fnType As Integer) As Integer


' 最初にこれでテーブルを作ってね
' create table saito (xxx text primary key);

Private Sub PostgreSQL_Update()

    Dim hEnv As Long
    Dim hDBc As Long
    Dim hstmt As Long
    Dim rc As Integer

    rc = SQLAllocEnv(hEnv)
    rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, hDBc)
    ' データソースも忘れずに作ってからですよ。
    rc = SQLConnect(hDBc, "PostgreSQL", SQL_NTS, "saito", SQL_NTS, "",
SQL_NTS)

    'INSERT
    rc = SQLAllocHandle(SQL_HANDLE_STMT, hDBc, hstmt)
    ' AUTO_COMMIT DISABLE
    'rc = SQLSetConnectOption(hDBc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON)
    rc = SQLExecDirect(hstmt, _
        "insert into saito values('SAITO');", SQL_NTS)
    rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt)
    MsgBox "INSERT"
    'UPDATE
    ' ****************************************************************
    rc = SQLSetConnectOption(hDBc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF)
    ' ****************************************************************
    rc = SQLAllocHandle(SQL_HANDLE_STMT, hDBc, hstmt)
   ' rc = SQLExecDirect(hstmt, "BEGIN;", SQL_NTS) <- BAD script
    rc = SQLExecDirect(hstmt, _
        "update saito set xxx = 'したよ' where xxx = 'SAITO';", SQL_NTS)
    MsgBox "トランザクション内更新中です。他で覗いてみてね。"
    'rc = SQLExecDirect(hstmt, "END;", SQL_NTS) <- BAD script
    ' ****************************************************************
    rc = SQLTransact(hEnv, hDBc, SQL_COMMIT)
    rc = SQLSetConnectOption(hDBc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON)
    ' ****************************************************************
    MsgBox "トランザクションの外にでました。"
    rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt)
    rc = SQLDisconnect(hDBc)
    rc = SQLFreeHandle(SQL_HANDLE_DBC, hDBc)
    rc = SQLFreeHandle(SQL_HANDLE_ENV, hEnv)

    ' 通常はきちんとエラー対策しないと、とんでもないことになりますよ

End Sub





pgsql-jp メーリングリストの案内