Notes C API探訪: NSFSearch(関数)(その1)
ここまで@式やサマリーバッファといった事項について紹介してきましたが、それもこれもこのNSFSearch関数をご紹介したいがためでした。
NSFSearch
NSFSearch関数には、2つの機能があります。
1. データベースの中から条件に合う文書を検索する
2. ディレクトリから条件に合うファイル、又はサブディレクトリを検索する
このように、対象(データベースハンドル)が何を指すかで、検索する対象が変わります。
その辺りについて、以下の記事で簡単に触れています。
では、NSFSearch関数の仕様を見てみましょう。
#include <nsfsearc.h>
STATUS LNPUBLIC NSFSearch (
DBHANDLE hDB,
FORMULAHANDLE hFormula,
char far *ViewTitle,
WORD SearchFlags,
WORD NoteClassMask,
TIMEDATE far *Since,
NSFSEARCHPROC EnumRoutine,
void far *EnumRoutineParameter,
TIMEDATE far *retUntil);
hDBは、データベースハンドル(またはディレクトリハンドル)を指定します。
hFormulaは、@式ハンドルを指定します。
ViewTitleは、選択式に「@ViewTitle」を使っている場合に、ビューの名前を指定します。それ以外はヌルポインタを指定します。
SearchFlagsは、検索フラグを指定します(後述)。
NoteClassMaskは、検索する文書の文書クラスを指定します。
Sinceは、特定の日時以降に作成、または変更された文書の検索に限定する場合に、その日時を指定します。
EnumRoutineは、NSFSearch関数が検索して文書、またはファイル/ディレクトリを見つけた際に呼び出されるコールバック関数を指定します(後述)。
EnumRoutineParameterは、EnumRoutine関数を呼び出す際に含める、汎用的なパラメータへのポインタを指定します(後述)。
retUntilは、検索終了時刻を受け取る変数へのポインタを指定します。この時刻を、次回の検索時にSince値として含めれば、検索範囲を時間で絞り込めるようになります。
非常に引数が多いですね。細かく見ていきます。
SEARCH_XXXフラグ
まず、検索フラグ(SearchFlags)で定義されているビットフラグは以下の通りです。
/* Search Flag Definitions */
#define SEARCH_ALL_VERSIONS 0x0001 /* Include deleted and non-matching notes in search */
/* (ALWAYS "ON" in partial searches!) */
#define SEARCH_SUMMARY 0x0002 /* TRUE to return summary buffer with each match */
#define SEARCH_FILETYPE 0x0004 /* For directory mode file type filtering */
/* If set, "NoteClassMask" is treated */
/* as a FILE_xxx mask for directory filtering */
#define SEARCH_NOTIFYDELETIONS 0x0010 /* Set NOTE_CLASS_NOTIFYDELETION bit of NoteClass for deleted notes */
#define SEARCH_ALLPRIVS 0x0040 /* return error if we don't have full privileges */
#define SEARCH_SESSION_USERNAME 0x0400 /* Use current session's user name, not server's */
#define SEARCH_NOABSTRACTS 0x1000 /* Filter out "Truncated" documents */
#define SEARCH_DATAONLY_FORMULA 0x4000 /* Search formula applies only to
data notes, i.e., others match */
SEARCH_ALL_VERSIONSは、削除された文書やマッチしなかった文書も検索に含めます。
SEARCH_SUMMARYは、一致するたびにサマリーバッファを返すようにします。
SEARCH_FILETYPEは、ディレクトリモードでファイルを検索するようにします。こうすると、引数NoteClassMaskは、文書マスク(NOTE_CLASS_xxx)ではなく、ファイルマスク(FILE_xxx)として解釈され、ファイルやディレクトリを検索するようになります。
SEARCH_NOTIFYDELETIONSは、削除された文書を検索した時に、削除された文書を示すように、SEARCH_MATCH構造体のNoteClassMaskメンバーで、NOTE_CLASS_NOTIFYDELETIONビットが立つようになります。
SEARCH_ALLPRIVSは、完全な権限を持っていない場合にエラーを返します。
SEARCH_SESSION_USERNAMEは、サーバとしてではなく、現在のセッションユーザとして関数を使用するようにします。
SEARCH_NOABSTRACTSは、切り捨てられた文書は検索しません。
SEARCH_DATAONLY_FORMULAは、検索式を一般文書(設計文書ではない)にのみ適用します。
NSFSEARCHPROC
次にコールバック関数(EnumRoutine)です。
検索が成功するたびに呼び出されるコールバック関数は、以下のような仕様で呼び出し側が準備する必要があります。
typedef STATUS (LNCALLBACKPTR NSFSEARCHPROC)(
void far *EnumRoutineParameter,
SEARCH_MATCH far *SearchMatch,
ITEM_TABLE far *SummaryBuffer);
EnumRoutineParameterは、NSFSearch関数で渡した汎用パラメータへのポインタ、EnumRoutineParameterがそのまま渡されます。
例えば、コンテナオブジェクトへのポインタを渡すと、コールバック関数内にポインタが渡されるので、検索した結果をポインタを通じてコンテナに保管すれば、NSFSearch関数を呼び出したプログラムで検索結果を得ることができる、といった使い方ができます。
SearchMatchは、SEARCH_MATCH構造体へのポインタが渡されます(後述)。
SummaryBufferは、検索フラグSEARCH_SUMMARYを指定することで、名前付きサマリーバッファ(ITEM_TABLE構造体)へのポインタが渡されます。
SEARCH_MATCH構造体
コールバック関数で受け取れるSEARCH_MATCH構造体は、以下のような仕様になっています。
typedef struct {
GLOBALINSTANCEID ID; /* identity of the note within the file */
ORIGINATORID OriginatorID; /* identity of the note in the universe */
WORD NoteClass; /* class of the note */
BYTE SERetFlags; /* MUST check for SE_FMATCH! */
BYTE Privileges; /* note privileges */
WORD SummaryLength; /* length of the summary information */
/* WORD TUALength; length of the $TUA item value; must be requested with SEARCH1_RETURN_THREAD_UNID_ARRAY */
/* 56 bytes to here */
/* now comes an ITEM_TABLE with Summary Info */
/* now comes the optional $TUA item value. It is in host format. */
} SEARCH_MATCH;
IDは、インスタンス文書が設定されます(後述)。
OriginatorIDは、作成者IDが設定されます(後述)。
NoteClassは、文書クラスが設定されます。
SERetFlagsは、検索結果のフラグが設定されます(後述)。
Privilegesは、権限フラグが設定されます。
SummaryLengthは、サマリーバッファ(ITEM_TABLEとそのデータ)の全体のサイズが設定されます。
なお、SEARCH_MATCH構造体を受け取ったら、ポインタから直接アクセスせずに、memcpyでローカル変数にコピーしてから使うように注意書きがあるので、指示に従った方がいいでしょう。
GLOBALINSTANCEID
SEARCH_MATCH構造体のID(GLOBALINSTANCEID)は、以下のような仕様になっています。
typedef struct {
DBID File; /* database Creation time/date */
TIMEDATE Note; /* note Modification time/date */
NOTEID NoteID; /* note ID within database */
} GLOBALINSTANCEID;
Fileは、データベースの作成日時です。
Noteは、文書の更新日時です。
NoteIDは、文書IDです。
ORIGINATORID
SEARCH_MATCH構造体のOriginatorID(ORIGINATORID)は、以下のような仕様になっています。
typedef struct ORIGINATORID_tag {
DBID File; /* Unique (random) number */
/* (Even though this field is called "File", */
/* it doesn't have anything to do with the file!) */
TIMEDATE Note; /* Can be Original Note Creation time/date */
/* (see OID.Note comment above) */
/* (THE ABOVE 2 FIELDS MUST BE FIRST - UNID */
/* COPIED FROM HERE ASSUMED AT OFFSET 0) */
DWORD Sequence; /* LOW ORDER: sequence number, 1 for first version */
/* HIGH ORDER WORD: flags, as above */
TIMEDATE SequenceTime; /* time/date when sequence number was bumped */
} ORIGINATORID;
Fileは、ユニークな番号です。
Noteは、オリジナルの文書の作成日時で、Fileと合わせてUniversalNoteID(UNID)を意味します。
Sequenceは、シーケンス番号です。
SequenceTimeは、シーケンス番号が更新された日時です。
SERetFlags
SEARCH_MATCH構造体のSERetFlagsのビット定義は、以下のようになります。
#define SE_FNOMATCH 0x00 /* does not match formula (deleted or updated) */
#define SE_FMATCH 0x01 /* matches formula */
#define SE_FTRUNCATED 0x02 /* document truncated */
#define SE_FPURGED 0x04 /* note has been purged. Returned only when SEARCH_INCLUDE_PURGED is used */
#define SE_FNOPURGE 0x08 /* note has no purge status. Returned only when SEARCH_FULL_DATACUTOFF is used */
#define SE_FSOFTDELETED 0x10 /* if SEARCH_NOTIFYDELETIONS: note is soft deleted; NoteClass&NOTE_CLASS_NOTIFYDELETION also on (off for hard delete) */
#define SE_FNOACCESS 0x20 /* if there is reader's field at doc level this is the return value so that we could mark the replication as incomplete*/
#define SE_FTRUNCATT 0x40 /* note has truncated attachments. Returned only when SEARCH1_ONLY_ABSTRACTS is used */
通常、SE_FMATCHフラグをチェックして、@式でマッチした文書であるかを確認します。
まとめ
NSFSearch関数は、それ自体はデータベースに対して条件に合う文書を検索する、またはディレクトリに対して条件にあるファイルやディレクトリを検索する、わかりやすい機能を提供しています。しかし、検索条件については@式をコンパイルする必要があったり、結果はコールバック関数で通知されたり、結果自体はSEARCH_MATCH構造体やサマリーバッファで受け取ったりと、機能が豊富なだけに、なかなか一筋縄ではいきません。また、私でも細かいフラグの定義など、未だに謎な部分も正直あります。
次回以降で、サンプルコードを交えて、NSFSearch関数の使い方を一緒に学べたらと思っています。