tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルvb6でaccessのデータ型が長いテキストが読み込めない
記事No16679
投稿日: 2024/02/02(Fri) 11:17
投稿者たろう
vb初心者のたろうです、よろしくお願い致します。

win11
vb6
Access Microsoft365 MSO

vb6でaccessのデータを読み込んでいますが
accessのデータ型が長いテキストの項目(項目名「LongText」)が読み込めません。
項目名「LongText」には改行が含まれることもありますが、改行が含まれないデータでも読み込めません。
データ型を短いテキストにすれば改行が含まれていても問題なく読み込めます。

下記がその読み込み部分です。


Public TestDatabase As ADODB.Connection
Public TestTable00  As ADODB.Recordset
dim STest as string

TestTable00.Open "SELECT * FROM T_Test", TestDatabase
If Not TestTable00.EOF Then
   If Not IsNull(TestTable00![LongText]) Then  'step1
      STest = TestTable00![LongText]            'step2                              
   Else
      STest  = ""                        'step3
   End If
End If
TestTable00.Close


まず普通に実行すると「実行時エラー5 プロシージャの呼び出し、または引数が不正です。」となります。
エラーになっている箇所は「step2」で
「データのチェックができません。nullの使い方が不正です」となります。
次はシングルステップで進み「step1」のTestTable00![LongText]部分にカーソルをあてるときちんと登録されている内容が表示されますが、
一度カーソルを別のところにもっていってからまたカーソルをあてると、なぜかNullと表示されてしまいます。
そうすると「step2」ではなく「step3」に進むのでエラーはでません。
ブレイクポイントを置かずに実行すると、「step1」でnullと判断されずに「step2」に進むのですが、「step2」に来た時点でなぜかTestTable00![LongText]がnullになってしまっていてエラーになるようです。


どうしてこのようなことが起こってしまうのか皆目見当がつきません。
また、どのように記述すればそのような現象が起きずにすむのかも分かりません。
もしなにかわかる方がいらっしゃいましたら教えていただけると助かります。
どうぞよろしくお願いいたします。

[ツリー表示へ]
タイトルRe: vb6でaccessのデータ型が長いテキストが読み込めない
記事No16680
投稿日: 2024/02/05(Mon) 11:00
投稿者魔界の仮面弁士
なかなか厄介な問題ですね。


> accessのデータ型が長いテキストの項目(項目名「LongText」)が読み込めません。

エラーが発生した行に含まれている文字の長さは何文字ですか?
該当フィールドの文字列内に非可読文字――たとえば ChrW(0) など――が混入していませんか?

特定の文字が原因で誤動作を引き起こした経験があるので、
もしも VB6 では発生するが、Access VBA 側であれば発生しないのであれば、
VBA にてその中身を確認してみてください。

Public Function DumpText(ByVal Value As Variant) As String
    Dim S As String: S = ""
    Dim B() As Byte: B = "" & Value
    Dim P As Long
    For P = LBound(B) To UBound(B)
        S = S & Right$("00" & Hex(B(P)), 2)
    Next
    DumpText = S
End Function


なお当方では、とあるデータベースへの ODBC リンクテーブルに対して、
vbNullString な文字列を読み書きしたときにエラーになる事象を経験したことがあります。
それもトラップできる実行時エラーではなく、いわゆる一般保護違反でクラッシュする事象です。

この時は ODBC Driver のバグであったことが後に判明したのですが、
環境側の不具合が修正されるまでの間は、対症療法的に
 ''' 修正前
 'If IsNull(rs.Fields(0).Value) Then
 ' s0 = ""
 'Else
 ' s0 = CStr(rs.Fields(0).Value)
 'End If
 'rs.Fields(1).Value = s1
 
 ''' 修正後
 s0 = "" & rs.Fields(0).Value
 rs.Fields(1).Value = "" & s1
のようにして対応していました。
空文字列と連結することで、 Null や vbNullString を "" に置き換えるという回避策です。
今回の障害と関係するかは分かりませんが、一度試してみてはいかがでしょう。


> 項目名「LongText」には改行が含まれることもありますが、改行が含まれないデータでも読み込めません。

今回の事象を抜きにしても、その列名はあまり良くないですね。
LongText は予約語なので、フィールド名に使うことは避けた方が無難です。

予約語を SQL 中で使う場合、[〜] などで囲むなどのエスケープ処理が必要になるなど、
使い勝手が悪いですし、誤動作の要因にもなりえるため、別の名前の方が安全です。
(そのほか、No とか Name とか Date といった列名もトラブルの元です)

予約語の一覧はこちら。
https://learn.microsoft.com/ja-jp/office/troubleshoot/access/reserved-words?WT.mc_id=DT-MVP-8907


> If Not IsNull(TestTable00![LongText]) Then  'step1
それは省略表記ですよね。列の値ではなく列そのものを渡していますので、データ型を確認すると、
 Debug.Print TypeName(TestTable00![LongText])
は、"String" や "Null" などにはならないはずです。

COM オブジェクトに対する暗黙の自動型変換はパフォーマンス劣化の要因にもなりますので、面倒がらずに
 If Not IsNull(TestTable00![LongText].Value) Then
 If Not IsNull(TestTable00("LongText").Value) Then
 If Not IsNull(TestTable00.Fields("LongText").Value) Then
 If Not IsNull(TestTable00.Fields.Item("LongText").Value) Then
 If Not IsNull(TestTable00.Collect("LongText")) Then
などと記述することが望ましいです。
これらの表記であれば、取得されるのはフィールドではなくフィールド値となります。


> STest = TestTable00![LongText]            'step2
これも本来は、
 STest = TestTable00![LongText].Value
 STest = TestTable00.Fields("LongText").Value
 STest = TestTable00.Collect("LongText")
ですね。CStr を併用するかどうかはお好みで。


> まず普通に実行すると「実行時エラー5 プロシージャの呼び出し、または引数が不正です。」となります。
> エラーになっている箇所は「step2」で
> 「データのチェックができません。nullの使い方が不正です」となります。
コンパイルエラーではなく実行時エラーということは分かりましたが、
質問文にある上記 2 つのエラーメッセージが一貫していないようです。
メッセージの異なる両者の違いはなんでしょうか。
「普通に実行する」以外の実行手段として、具体的にどのように実行したのでしょうか?

また、"データのチェックができません。" というエラーメッセージは聞いたことがありませんが、
ひとまず、VBA エラー 94「Null の使い方が不正です。」では無いという認識で良いでしょうか。(Null ではなく null 表記ですし)
正確性を期すため、Err.Description の内容だけでなく、Err.Number と Err.Source も教えてください。


> 次はシングルステップで進み「step1」のTestTable00![LongText]部分にカーソルをあてるときちんと登録されている内容が表示されますが、
> 一度カーソルを別のところにもっていってからまたカーソルをあてると、なぜかNullと表示されてしまいます。
デバッグ実行ではなく、コンパイル実行した場合にも、同じ個所でエラーになりますか?

残念ながら VB6 開発環境は、Windows 11 での動作が保証されていません。
サポートされているのはランタイムのみであり、開発環境ではありません。

もしも EXE から実行した場合はエラー箇所が変わる(あるいはエラーにならない)場合は、
コンパイルオプションを、(標準の)ネイティブコードではなく、P-Codeに変更してみてください。
そのうえで P-Code の時だけ発生するようであれば、デバッガの不具合という可能性もありそうです。


過去ログ No15594 などでも触れられていますが、VB6.0 で開発するのであれば、
開発機には XP まで、せいぜい Vista までの環境、それも 32bit版を用意しておいた方が無難です。
※動作検証用の端末とは別に用意する。

参考までに下記も読んでみてください。とはいえ OS の修正プログラムなどで解消されることもあるので、
当時発生していたエラーが、いつの間にか発生しなくなっていた…という事象を自分は何度か経験しています。
https://hanatyan.sakura.ne.jp/patio/read.cgi?no=272


あとは、Recordset の CursorLocation を変更することで改善するかどうかを調べてみるとか。
adUseServer なら adUseClient に。adUseClient なら adUseServer にして動作を確認するということです。

現在の設定を確認しておきたいので、TestTable00.Open 後に下記を実行してみてください。

Debug.Print "CursorLocation="; TestTable00.CursorLocation
Debug.Print "    CursorType="; TestTable00.CursorType
Debug.Print "      LockType="; TestTable00.LockType


> そうすると「step2」ではなく「step3」に進むのでエラーはでません。
> ブレイクポイントを置かずに実行すると、「step1」でnullと判断されずに「step2」に進むのですが、
> 「step2」に来た時点でなぜかTestTable00![LongText]がnullになってしまっていてエラーになるようです。
ウォッチ ペインなどに、何らかの副作用を含む式が入っていた、ということはないでしょうか。

[ツリー表示へ]
タイトルRe^2: vb6でaccessのデータ型が長いテキストが読み込めない
記事No16681
投稿日: 2024/02/06(Tue) 13:56
投稿者たろう
魔界の仮面弁士様、色々と詳しくありがとうございます。

まず結果ですが、下記のように対応したら出来ました!
本当にどうしていいかわからず困っていましたので助かりました。

>  ''' 修正前
>  'If IsNull(rs.Fields(0).Value) Then
>  ' s0 = ""
>  'Else
>  ' s0 = CStr(rs.Fields(0).Value)
>  'End If
>  'rs.Fields(1).Value = s1
>  
>  ''' 修正後
>  s0 = "" & rs.Fields(0).Value
>  rs.Fields(1).Value = "" & s1
> のようにして対応していました。
> 空文字列と連結することで、 Null や vbNullString を "" に置き換えるという回避策です。




下記は「Value」に引き渡した時点でnullになってしまい結果を得ることができませんでした。

> Public Function DumpText(ByVal Value As Variant) As String
>     Dim S As String: S = ""
>     Dim B() As Byte: B = "" & Value
>     Dim P As Long
>     For P = LBound(B) To UBound(B)
>         S = S & Right$("00" & Hex(B(P)), 2)
>     Next
>     DumpText = S
> End Function


下記の件、大変参考になりました。
列名でNameやDateも使用していましたので、これからは気を付けたいと思います。

> 今回の事象を抜きにしても、その列名はあまり良くないですね。
> LongText は予約語なので、フィールド名に使うことは避けた方が無難です。
>
> 予約語を SQL 中で使う場合、[〜] などで囲むなどのエスケープ処理が必要になるなど、
> 使い勝手が悪いですし、誤動作の要因にもなりえるため、別の名前の方が安全です。
> (そのほか、No とか Name とか Date といった列名もトラブルの元です)


こちらも気を付けたいと思います。

> COM オブジェクトに対する暗黙の自動型変換はパフォーマンス劣化の要因にもなりますので、面倒がらずに
>  If Not IsNull(TestTable00![LongText].Value) Then
>  If Not IsNull(TestTable00("LongText").Value) Then
>  If Not IsNull(TestTable00.Fields("LongText").Value) Then
>  If Not IsNull(TestTable00.Fields.Item("LongText").Value) Then
>  If Not IsNull(TestTable00.Collect("LongText")) Then
> などと記述することが望ましいです。


"データのチェックができません。"というメッセージは自分がエラーの時にだしていたメッセージでした。
色々自分の中で整理できずに、大文字小文字なども適当になっており申し訳ありませんでした。

また質問することがありましたら、情報はきちんと正確にお伝えするように気を付けます。

開発環境は今のところどうにもならないのですが、たくさんの問題点や確認しなくてはいけない点を細かく教えていただき感謝しております。

本当にありがとうございました。

[ツリー表示へ]