先日、とある事がきっかけで発覚した現象。

Lotus Notes/Domino では、エージェント終了時に、
基本的にメモリは開放されるはずだが、
Error が発生した場合は、メモリ解放が完全には行われていない(…っぽい)

 ※ここで言う Error とは、
  「型が一致しない」や、「RESUMEが無い」等々、
  一般的に「on error」で検出するエラーの事。


そこで興味本位から、とある実験を行なってみる。
(もちろんローカルPC上で)

実験用に作成したエージェントは次のとおり。
実行させる場合は自己責任で実行させて下さい

----- < Sample Start > -----
Sub Initialize
  '宣言部
  'テスト用文字
  Const TEST_STR = "a_"
  'ループ終了値
  Const LOOP_MAX = 300000
  'ループカウンタ
  Dim loopCnt As Long
  
  '処理部
  For loopCnt = 0 To LOOP_MAX
    Call testSub( TEST_STR & Cstr(loopCnt) )    '引数として数値変換不能な文字列を渡す
    Print Cstr(loopCnt) & " 件目:" & Error$    'エラーメッセージを出力
  Next
  
  Print "処理終了"
  
End Sub
Sub testSub(longCnt As String)
  '宣言部
  Dim testInt As Integer
  
  '処理部
  On Error Goto errorHandler
  
  testInt = longCnt                 'ここでエラー発生
  
  Exit Sub                      '絶対に通らない Exit Sub
  
errorHandler:
  Exit Sub
  
End Sub
----- < Sample End > -----


もうお分かりだろう。

要は、先に書いた Error を
ループの中で300000回繰り返し発生させるだけである。

実行すると、最初のうちは「T003 型が一致しません」というエラーが表示される。

しかし、ある程度のループ回数を超えると、
「Lotus Notes がサポートできるメモリ分割の最大数が限度を超えています。」という
エラーメッセージに変わってしまう。

 ※マシンスペックにもよるだろうが、
  当方が使用している貧弱なマシンではこれで十分…(泣)

こうなってしまうと、
エージェントが終了した後も上記メッセージが頻発し、
大抵の場合、赤画面が表示されて落ちる。

これがもしも、サーバエージェントだったらどうなるか…?

要は、ループの中でエラーハンドラを使用する際には注意が必要…という話
今回は、Notes に特化した話

あくまでも『備忘録』として残していくつもりなので、ご理解を…


今回の客先から、下記のような要件がありました。


【要件】
     開発DB(以下:DB)は、一般ユーザには公開したくない。
    設計者以上の権限を持つユーザ(管理者等)、
    もしくは[System]ロール保持ユーザ(情シ部門)のみが
    オープン出来るようにしたい。

      ※ここで言うオープンとは、ワークスペースからのオープン

    ただ、他のアプリから、ロジックを通して使用されることは多々ある。


上記要件を満たすため、まず頭に思いつくのは『データベーススクリプト』

ところが今回の場合、ロールの判定とACLの判定とが発生する。

ACLの判定は、『LotusScript』を使うほうが楽!!
(CurrentAccessLevel 等)

かたやロールの判定は、『@関数式』を使うほうが圧倒的に楽!!
(@UserRoles 等)

  NotesDatabase.QueryAccessRoles のようなメソッドもあるが、
 ロールを全く持たないユーザの場合、
 Nothing ではなく、"" をもつ配列が返ってくるのが難点
 さらに言えば、空の戻り値に対して ArrayGetIndex 関数が使用できない


この為、Evaluate 関数を使用してロールの判定を行ない、
ACLは通常通りの判定を行った

---------- 以下:作成ロジック ----------
Sub Postopen(Source As Notesuidatabase)
  'リテラル情報
  Const ROLE_CHK_MACRO = "@IsMember(""[System]"";@UserRoles)"

  '宣言部
  Dim roles As Variant

  Dim roleFlg As Boolean
  Dim aclFlg As Boolean

  '処理部
  '所持ロール判定
  roles = Evaluate(ROLE_CHK_MACRO)
  Select Case roles(0)
  Case "1"
  'ロール有り
    roleFlg = True
  Case Else
  'ロール無し
    roleFlg = False
  End Select


  'ACL判定
  Select Case Source.Database.CurrentAccessLevel
  '設計者以上
  Case Is >= 5
    aclFlg = True
  '作成者以下
  Case Else
    aclFlg = False
  End Select


  'ロール不所持かつ編集者以下のユーザはオープン禁止
  If (roleFlg = False) And (aclFlg = False) Then
    Call Source.Close
  End If

End Sub
----------------------------------------

今回も特に難しい事はしていないので、説明は不要だろう。


ただ、ワークスペースからDBアイコンをダブルクリックした直後に
「Ctrl + Break」を押下されると、
上記ロジックの途中で処理が中断されるため、
「要求により処理を中断しました」というメッセージと共に
DBが開かれてしまう。。。

これは、Notes の仕様…というか、ご愛嬌(笑)
数値の剰余計算を行なうための『mod』関数

数値を扱うプログラムを作ったことのある人なら、
おそらく大多数の人は使ったことがあるのではなかろうか?

ところが、この『mod』関数…

戻り値が Integer 型ということで、
あまりにも大きな数値を扱う場合には桁数が足りないという問題が発生する

戻り値が Currency 型だと良いのに…と思ったところから、
結果、無いのなら自分で作ろう!!ということで、以下のような関数を作った

Function modCur(num1 As Currency,num2 As Currency) As Currency
'-----------------------------------------------------------------------------
'処理名 :剰余取得
'-----------------------------------------------------------------------------
'概 要 :第一引数を第二引数で除算した場合の剰余を返す
'引 数 1)num1 :割られる数
' 2)num2 :割る数
'
'戻り値 :Currency :剰余
'
'-----------------------------------------------------------------------------

'譲与取得
modCur = num1 - (Ccur(Int(num1 / num2)) * num2)

End Function

計算内容は非常にシンプルなものなので、特に説明の必要はないだろう

現在の業務では、大きな数値を扱うことが多いため、
非常に重宝している関数である
最近、アメブロに登録しているお気に入りの表示がおかしい…

特に『ライ○ドア』のBlog更新状況が
きちんと取得出来ていないもよう…

俺のBlog友達にはラ○ブドアブロガーが多いから
何とか以前のように復旧して欲しいと切に願う今日この頃…