[[PSSdev]] #contents * 概要 Ver.7.0 の DB は Ver.6.x 以前の DB と比べて大きく変化している. ここでは,Ver.6.x 以前の DB ファイルを Ver.7.0 形式に変換するための手順を述べる. * PSS の各バージョンと DB/Log,レジストリエントリの関係 ** 調査結果表 | 本体 | 既定のインストール先 | データフォルダ || DB | ファイル名 | レジストリ || Log | ファイル名 | レジストリ | | Ver.2.0 | PSS2 | Datas || pdb | DBv3.pss | Pss/DBv3/filename || N/A | N/A | N/A | | Ver.3.0 | Pss2 | Datas || pdb | DBv3.pss | Pss/DBv3/filename || pdblog0 | translog.txt | Pss/Options/LogPath | | Ver.4.0 | Pss2 | Datas || pdb | DBv3.pss | Pss/DBv3/filename || pdblog0 | translog.txt | Pss/Options/LogPath | | Ver.4.1 | Pss2 | Datas || pdb | DBv3.pss | Pss/DBv3/filename || pdblog0 | translog.txt | Pss/Options/LogPath, PointfilePath | | Ver.4.2 | Pss2 | Datas || pdb | DBv3.pss | Pss/DBv3/filename || pdblog1 | translog.psslog | Pss/Options/LogPath | | Ver.4.3 | Pss2 | Datas || pdb | database.pssdb4 | Pss/DBv3/filename || pdblog1 | translog.psslog | Pss/Options/LogPath | | Ver.5.x | Pss5 | data || pdb2 | database.pssdb5 | Pss5/database/filename || pdblog2 | translog.psslog5 | Pss5/Options/LogPath | | Ver.6.x | Pss5 | data || pdb2 | database.pssdb6 | Pss5/database/filename6 || pdblog2 | translog.psslog5 | Pss5/Options/LogPath | | Ver.7.0 | PSS7 | data || pdb3 | database.pssdb7 | PSS7/config/database-path || - | - | - | DB と Log は 2004.03.22 現在における,DB/Log 操作ライブラリ名称を示す.ただし,pdblog2 は pdblog2.h/cpp で実装され,pdblog ネームスペースに存在する. ** 結果の考察 上記の表を見る限り,Ver.4.1 以前の DB/Log は pdb/pdblog0 で操作できる.ファイル名も統一されているため,Ver.2.0〜Ver.4.1 は pdb/pdblog0 で統一的に操作可能である. Ver.4.2〜Ver.4.3 は,Log が pdblog1 に変更されている. ただし,Ver.4.3 以前はレジストリエントリが統一されているので,同一のレジストリエントリからファイル名を取り出し,拡張子に応じて履歴操作ライブラリを変更することで対応できる. Ver.5.0 からは DB/Log ともに UNICODE 対応のために大幅な変更がなされているが,レジストリエントリも別のものになっているので,対応は容易だろう. Ver.5/6 の違いは DB の形式が異なることであるが,ライブラリは同一のものを使っている.そのため,拡張子に応じて pdb2::Tree::load5/save5 と pdb2::Tree::load6/save6 を使い分けることになる. ** アップデートに関する所見 いずれにせよ,Log については Ver.6 用に pdblog0 -> pdblog1, pdblog1 -> pdblog2 変換ライブラリが pdblog_translator.h 用意されている.レジストリエントリや拡張子に応じて適切な変換ライブラリを用いることで,pdblog2 形式に変換することが可能であろう. DB の変換についても同様であるが,変換ライブラリについては実は不要であり,pdb2 の load5 メソッドで pdb 形式(つまり非UNICODE形式)ファイルを扱うことが出来る. つまり,レジストリエントリや拡張子に応じて適切な読み込みメソッド (load5 or load6) を用いることで,pdb2 形式に変換することが可能となる. * アップデート手順 DB のアップデートと Log のアップデートに分けて実行する. ** DB のアップデート手順 - Ver.6.x 用 DB があれば,Ver.7.0 形式に変換する. -- Ver.6.x 用レジストリエントリを検索し,存在すれば pdb2::Tree::load6 で pdb2 オブジェクトを作成する. - Ver.5.x 用 DB があれば,Ver.6.x 形式を経由して Ver.7.0 形式に変換する. -- Ver.5.x 用レジストリエントリを検索し,存在すれば pdb2::Tree::load5 で pdb2 オブジェクトを作成する. - Ver.4.x 用 DB があれば,Ver.6.x 形式を経由して Ver.7.0 形式に変換する. -- Ver.4.x 用レジストリエントリを検索し,存在すれば pdb2::Tree::load5 で pdb2 オブジェクトを作成する. - 全く異なるアプローチとして,レジストリエントリの検索と読み込み処理を切り分けることも可能であろう. -- まず 各レジストリエントリを検索して,ファイル名を取得する. -- 取得できたらファイル名の拡張子に応じて pdb2::Tree::load5/load6 を実行し,pdb2 オブジェクトを作成する. - pdb2 オブジェクトを pdb3_converter.h 内のコンバータで変換する. ** Log のアップデート手順 - Pss5/Options/LogPath を検索し,存在すれば Ver.5/6 用 Log である. -- pdblog2 オブジェクトを得る. - Pss/Options/LogPath を検索し,存在すれば Ver.4.x 以前用の Log である. -- 拡張子が .psslog であれば pdblog1 で読み込み,pdblog_translator によって pdblog2 オブジェクトに変換する. -- 拡張子が .txt であれば pdblog0 で読み込み,pdblog_translator によって pdblog2 オブジェクトに変換する(このとき pdblog1 オブジェクトを経由する).また,Point 用ファイルがある可能性があるため,これも pdblog_translator で変換する. - 得られた pdblog2 オブジェクトを pdb3_converter を用いて pdb3 形式に変換する.DB が存在していれば問題IDも適切に割り振ることが可能である. * pdb2 + pdblog2 -> pdb3 の変換方法 pdb2 や pdblog2 オブジェクトが取得できれば,次は pdb3 オブジェクトへの変換である. (以下略) * DB7 同士のアップデート PSS7 の新バージョンがリリースされたときなどには,DB7 同士のアップデートが必要となる. これは pdb3 レイヤーではなく,SQLiteDB を直接操作することにより実装する. ** 考察 アップデートすべきテーブルは下記の4テーブルである. - question - section - element_info - folder ここで,問題データそのものである question と,それを含む section を分離して考えるべきである. ユーザの欲求としては, - (A) 新しく追加された問題集が欲しい - (B) 既存の問題集のうち更新された部分を差し替えたい が考えられる. A は従来の DB6 同士のアップデートで実現できていた部分であり,B は限定的に実現できていた部分である. 今回のDB構成では,一定以下の qid に対しては同期が保証されているため,B は比較的容易に実現できるが, A に対しては eid の制約がないため,完全な形でのアップデートは難しい. B が「比較的」であるのは,「既存の問題集の更新」が「問題の修正」のみではなく, 「問題の追加」であった場合には,section-table を更新する必要があるためである. A, B それぞれを''個別に''実現するための手法を述べる. - udb : アップデート用DB,main : 本DB とする. A の実現手法: - udb のフォルダツリーを走査し,main に含まれていないフォルダ・問題集を見つける. -- この部分では pdb3 を用いる. - そのフォルダ・問題集を追加するかどうかユーザに確認する. - mian にフォルダ・問題集を追加する. -- element_info, section, folder, question の更新が必要. -- この部分では SQLite の ATTACH を用いて,SQL クエリーレベルでの更新も行う. B の実現手法: - udb 内の問題で,既に main に含まれている問題のうち,utime が新しい問題を探し,更新する. -- これにより既存の問題集の更新における「問題の修正」がなされる. -- これは SQL 文の発行で OK. - udb 内の問題で,main に含まれていない問題のうち,udb での問題集パスが既に main にもある場合,無条件に main の該当する問題集に対してその問題を追加する -- section への追加と,question への問題データの追加が必要. -- こちらは pdb3 レイヤーでの実行が必要(問題集パスでの比較を行うため) 以上をふまえ,question テーブルに対しては無条件にアップデートを行うこととし,それ以外に対しては適宜ユーザへの確認を行いながら追加・更新処理を行うこととする. ** 手順 PSS 本体において,起動時に下記の手順で行われる PSS 起動シーケンス: - レジストリ読み込み -- データフォルダ未設定なら選択させて設定 -- 各ファイルの格納先確定 -- その際,各ファイルが存在しないならオリジナルからコピー.(MyDocuments配下の場合) - DB 読み込み - DB アップデート DB アップデート手順: - question-table : -- udb の qid のうち,main に存在しない qid があれば,その行を main に追加. -- udb の qid のうち,main に存在する qid について,main より新しい udb の行があればその行を「削除&挿入(SQLクエリーの単純化のため)」により更新. - section-table, folder-table, element_info-table -- 追加した qid を含む udb の section を「対象section」と呼ぶ. -- 対象section のうち,同じパスの section が main にあれば,その section に追加した qid を(存在しない場合に)追加する. -- 同じパスの section が main になければ, --- その対象section の element_info を main の element_info-table に追加.eidはNULL追加し,これを new-eid と呼ぶ. --- その対象section の qid を main の section に追加.sidはnew-eidとする. --- フォルダ構造を再現するため,対象sectionの上のフォルダを… 以下検討中.