vcpp-ml

1

[vcpp 00061027] OLE DBでの行の追加更新について

田口と申します。

OLE DBの使い方で質問があります。

Oracleに対して、OLE DBを使用してアクセスするプログラムを作成している
のですが、Oracle用のOLE DB Providerで、MSの MSDAORA とOracleの 
OraOLEDB で行の登録更新の動作が異なり、解決策が見出せず苦戦しており
ます。OLE DBは今回初めて使用するためまだよく理解していません。どなた
か、ご教授願えないでしょうか。

テーブルに、列名:AAA 型:varchar2(5)の列があります(5バイトの文字列)。
この列に5バイトの文字列を登録更新しようとすると、MSDAORAでは問題ない
のですが、OraOLEDBだとエラーとなってしまいます。
行の登録更新には、CRowsetクラスのInsert()とSetData()を使用しているの
ですが、これらが、DB_E_ERRORSOCCURRED (0x80040E21)を返してきます。
5バイト以下の文字列の登録更新ではエラーとなりません。列のサイズと同
じサイズの文字列を登録更新しようとすると、エラーとなってしまいます。

いろいろ調べてはみたのですが、解決できませんでした。
OraOLEDBの問題なのか、私のコーディングの問題なのか...
多分後者でしょう、私のOLE DBの使い方が未熟なんだと思います。
OLE DBの使い方でプロパティの設定など、まだ足らないところがあるのでしょ
うか?
よろしくお願いします。

#include <atlbase.h>
#include <atldbcli.h>
#include <atldbsch.h>
#include <comdef.h>

class CTestTable
{
public:
    char m_AAA[6];

    BEGIN_COLUMN_MAP(CTestTable)
        COLUMN_ENTRY(1, m_AAA);
    END_COLUMN_MAP()
};
void main()
{
    CoInitialize(NULL);
    HRESULT hr;
    CDataSource dbSource;
    CSession dbSession;
    CCommand <CAccessor<CTestTable> > dbTable;
    
    // OraOLEDB
    hr = dbSource.OpenFromInitializationString(
          (BSTR)CComBSTR(L"Provider=OraOLEDB.Oracle.1; \
                Password=aaa;User ID=bbb;Data Source=ccc"));    
    // MSDAORA
//    hr = dbSource.OpenFromInitializationString(
//            (BSTR)CComBSTR(L"Provider=MSDAORA.1; \
//                Password=aaa;User ID=bbb;Data Source=ccc"));
    hr = dbSession.Open(dbSource);

    CDBPropSet PropSet(DBPROPSET_ROWSET);
    PropSet.AddProperty(DBPROP_CANFETCHBACKWARDS, true);
    PropSet.AddProperty(DBPROP_CANSCROLLBACKWARDS, true);
    PropSet.AddProperty(DBPROP_IRowsetChange, true);
    PropSet.AddProperty(DBPROP_UPDATABILITY, \
        DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | \
        DBPROPVAL_UP_DELETE);

    hr = dbTable.Open(dbSession, "select aaa from test", &PropSet);
    strcpy(dbTable.m_AAA, "12345");     
    hr = dbTable.Insert();  // <-- DB_E_ERRORSOCCURREDとなる

    dbTable.Close();
    dbSession.Close();
    dbSource.Close();
    CoUninitialize();
}
1

[vcpp 00061026] Re: メモリマップトファイルでマッピング済みの領域の拡張

中村です。

At 01 Aug 2003 01:01:38 +0900 S.Suzuki wrote:
> 最初のプロセス100バイト。後から別のプロセスが5000バイトをマッピング
> すると、後のプロセスが、4097バイト目をアクセスした時点で
> 不正なアクセスで落ちてしまいます(ノーマルファイルでもページファイルでも)。
> 最初の100バイトは確かに超えていますが、おそらくページサイズ単位で
> マッピングされているので、2回目の5000バイト(2ページ分)は
> 正しくマッピングされていないということだと思います。
> #ちなみにノーマルファイルの場合、フォルダー上のファイルサイズ自体は
>   ちゃんと5000バイトになっているのですが。。。

> <勝手な予想>
> CreateFileMappingのサイズの指定は、一番最初に
> 行ったときだけ有効で、後から同じマッピングの名前を指定した場合は
> 最初の値が適用されるだけで、サイズの指定に意味はないのではないか?
> (最初より小さい場合は有効かもしれませんが)
> と考えています。
> </勝手な予想>

<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/createfilemapping.asp>

には、

> If this parameter matches the name of an existing named mapping object,
> the function requests access to the mapping object with the protection
> specified by flProtect.

と書いてありますので、他のパラメータは無視されると考えた方が良いのかもしれ
ません。

<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/sharing_files_and_memory.asp>

などをみると、二つ目以降のプロセスではOpenFileMappingを使うことを推奨して
いるように見えますし。

しかし、ファイルのサイズが増えてしまうのはなぜなんでしょう。そっちがバグな
のかもしれませんね。


-- 
Satoshi Nakamura <s...@zak.att.ne.jp>
1

[vcpp 00061025] Re: メモリマップトファイルでマッピング済みの領域の拡張

Suzukiです。
こんばんわ!
お返事ありがとうございます!

> おはよございます。
> またはずしましたか・・・(^^;

いえいえ。
貴重なご意見、大変参考になります。m(__)m

> たとえば、普通にオープンするファイルだった場合に他のプロセスがファ
> イルのサイズを変えると、別のオープン済みのプロセスは変化したサイズ
> までファイルポインタをシークできるはずですよね。
> これと同じようなメカニズムではないでしょうか?
> ファイルマッピングオブジェクトとはいえ、プログラムから直接ファイル
> にアクセスするのではなく、OS内部のキャッシュが実施されているはずで
> す。なので、一方のプロセスではたぶん範囲外だろうあたりのオフセット
> を指定されてもキャッシュ更新時に同期を取るだろうから、ご要望のこと
> はOSとして「できなければならない」ことではないかと。

なるほど。。。
確かに普通のファイルならそうですよね。
そうは思うのですが、、、


> 増殖させる大きさをOSのキャッシュサイズより大きくしたりして実験すると
> 可・不可の判断ができるような気がしますが・・・σ(^_^)はできると思いま
> すね。
> #時間がないのでテストできませんが・・・

(OSのキャッシュサイズの限界を超えてのテストはしていないのですが、、、)
じつは、テストプログラムをシンプルにして再度腰をすえて実験をしたのですが、
結果としては
最初のメールの質問1、2ともにNGでした。。。。
つまり、ノーマルファイル・ページファイルを問わず、2度目に最初の
マッピングサイズよりも大きい値を指定しても、最初のサイズを越えた
アクセスはできませんでした。。。

最初のプロセス100バイト。後から別のプロセスが5000バイトをマッピング
すると、後のプロセスが、4097バイト目をアクセスした時点で
不正なアクセスで落ちてしまいます(ノーマルファイルでもページファイルでも)。
最初の100バイトは確かに超えていますが、おそらくページサイズ単位で
マッピングされているので、2回目の5000バイト(2ページ分)は
正しくマッピングされていないということだと思います。
#ちなみにノーマルファイルの場合、フォルダー上のファイルサイズ自体は
  ちゃんと5000バイトになっているのですが。。。

<勝手な予想>
CreateFileMappingのサイズの指定は、一番最初に
行ったときだけ有効で、後から同じマッピングの名前を指定した場合は
最初の値が適用されるだけで、サイズの指定に意味はないのではないか?
(最初より小さい場合は有効かもしれませんが)
と考えています。
</勝手な予想>

> 是非結果を教えてくださいませ。

別の方からもレスをいただいていますが、やはり後から大きな
マッピングサイズを指定することによる共有メモリの拡張はNG
ということかな?と今思っています。

結局メモリマップトファイルによる動的なメモリ共有は
・決めうちの固定サイズのマッピングを、必要の応じ、増やしていく
・ノーマルファイルで共有し、サイズを拡張する場合は
  一旦全員のマッピングをCloseして、誰か一人がまず拡張してたあと
  また、再度全員マッピングをする。
・(DMでご指摘いただいただけで、未確認ですが)
  NTFSであるなら、Sparse file(FSCTL_SET_SPARSE)を利用してみる。

くらいかな、と思っています。
どなたかいい方法があれば教えてくださいませ。

ではでは。
記事検索
Amazon.co.jp
  • ライブドアブログ