やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

SQLite3学習 CLI起動引数(-A)Archive

 アーカイブ機能。

成果物

SQLite3 Archive形式

 SQLite3 ArchiveZIPtarのSQLite3版みたいなもの。それらより1%ほど大きくなるがSQL文やSQLite3コマンドで操作できる。

ヘルプ

sqlite3 -A
Wrong number of arguments.  Usage:
.archive ...             Manage SQL archives
   Each command must have exactly one of the following options:
     -c, --create               Create a new archive
     -u, --update               Add files or update files with changed mtime
     -i, --insert               Like -u but always add even if mtime unchanged
     -t, --list                 List contents of archive
     -x, --extract              Extract files from archive
   Optional arguments:
     -v, --verbose              Print each filename as it is processed
     -f FILE, --file FILE       Operate on archive FILE (default is current db)
     -a FILE, --append FILE     Operate on FILE opened using the apndvfs VFS
     -C DIR, --directory DIR    Change to directory DIR to read/extract files
     -n, --dryrun               Show the SQL that would have occurred
   Examples:
     .ar -cf archive.sar foo bar  # Create archive.sar from files foo and bar
     .ar -tf archive.sar          # List members of archive.sar
     .ar -xvf archive.sar         # Verbosely extract files from archive.sar
   See also:
      http://sqlite.org/cli.html#sqlar_archive_support

使ってみる

テストファイル作成

echo -e "aaa\nAAA" > A.txt
echo -e "bbb\nBBB" > B.txt

Archiveファイル作成

$ sqlite3 texts -Ac A.txt B.txt

 textsファイルが作成される。

ls -1 | grep texts
texts

ファイル一覧

 CLI

$ sqlite3 texts -At
A.txt
B.txt

一覧の詳細

sqlite3 texts -Atv
-rw-r--r--          8  2019-08-16 04:54:47  A.txt
-rw-r--r--          8  2019-08-16 04:54:47  B.txt

ファイル展開

 まずは元ファイルを削除する。

rm A.txt B.txt

 次にSQLite3アーカイブファイルの内容を展開する。

sqlite3 texts -Ax

 A.txt, B.txtファイルが出力されている。

cat A.xt
aaa
AAA
cat B.xt
bbb
BBB

SQLiteで見てみる

sqlite3 texts

 対話モードで開く。テーブル一覧する。

.tables

 sqlarというテーブルが出来ている。

sqlar

 テーブルの中身を見てみる。

.headers on
select * from sqlar;
name|mode|mtime|sz|data
A.txt|33188|1565931287|8|aaa
AAA

B.txt|33188|1565931287|8|bbb
BBB

 ファイル名、権限、更新日時、サイズ、内容が入っている。

 これでSQLでも操作できることがわかった。

挿入

 SQLiteアーカイブファイルに追加する。

 まずは追加する元ファイルを作成する。

echo -e "ccc\nCCC" > C.txt

 アーカイブファイルtextsC.txtを追加する。

sqlite3 texts -Ai C.txt

 一覧にてC.txtが存在することを確認。

sqlite3 texts -At
A.txt
B.txt
C.txt

更新

 ファイル内容の変更を確認する。削除はできない。一度作成されたらコマンドからは削除不可。

 まずはアーカイブファイルの確認。

sqlite3 texts -At
A.txt
B.txt
C.txt

 これをファイルシステムへ展開する。

sqlite3 texts -Ax

 カレントディレクトリには以下のようなファイルが存在する状態になる。

ls
A.txt  B.txt  C.txt  texts

 ここでA.txtファイルを削除する。

rm A.txt
ls
B.txt  C.txt  texts

 そしてB.txtの内容を編集する。

echo "ばばば" >> B.txt
bbb
BBB
ばばば

 この変更をアーカイブにマージする。

sqlite3 texts -Au *.txt
sqlite3 texts -At

 textsファイルをSQLite3で開く。

sqlite3 texts
select * from sqlar;
A.txt|33188|1565931287|8|aaa
AAA

C.txt|33188|1565932536|8|ccc
CCC

B.txt|33188|1565933322|18|bbb
BBB
ばばば

 B.txtの変更はされている。だが、A.txtファイルは削除されていない。

 ファイル削除するコマンドが見つからない。

ディレクトリを追加する

 テスト用にディレクトリとファイルを作成する。

mkdir -p ./D/DD
echo -e "ddd\nDDD" > ./D/DD/DDD.txt

 ディレクトリを追加する。

sqlite3 texts -Ai D

 一覧する。

sqlite3 texts -At
A.txt
B.txt
C.txt
D
D/DD
D/DD/DDD.txt

 詳細一覧する。

sqlite3 texts -Atv
-rw-r--r--          8  2019-08-16 04:54:47  A.txt
-rw-r--r--          8  2019-08-16 05:15:36  C.txt
-rw-r--r--         18  2019-08-16 05:28:42  B.txt
drwxr-xr-x          0  2019-08-16 05:39:42  D
drwxr-xr-x          0  2019-08-16 05:40:30  D/DD
-rw-r--r--          8  2019-08-16 05:40:30  D/DD/DDD.txt

 ディレクトリならmodedフラグが付与される。

 ファイルシステムから削除する。

rm -r A.txt B.txt C.txt D/

 アーカイブから展開する。

sqlite3 texts -Ax

 ディレクトリやその下にあるファイルも展開されていることを確認。

cat ./D/DD/DDD.txt
ddd
DDD

削除

 Archiveファイルの中身をSQLite3で見てみる。

sqlite3 texts ".headers on" "select * from sqlar;";
name|mode|mtime|sz|data
A.txt|33188|1565938716|8|aaa
AAA

C.txt|33188|1565938717|8|ccc
CCC

B.txt|33188|1565938717|18|bbb
BBB
ばばば

D|16877|1565938717|0|
D/DD|16877|1565938717|0|
D/DD/DDD.txt|33188|1565938717|8|ddd
DDD

 SQLDELETE文で削除してみる。

sqlite3 texts "delete from sqlar where name='A.txt'";

 削除されている。成功。

sqlite3 texts ".headers on" "select * from sqlar;";
name|mode|mtime|sz|data
C.txt|33188|1565938717|8|ccc
CCC

B.txt|33188|1565938717|18|bbb
BBB
ばばば

D|16877|1565938717|0|
D/DD|16877|1565938717|0|
D/DD/DDD.txt|33188|1565938717|8|ddd
DDD

 というか、なぜ削除はCLIコマンドでできないの? 不便。それとも見落としている?

ディレクトリの再帰的削除はされない

sqlite3 texts "delete from sqlar where name='D'";
sqlite3 texts ".headers on" "select * from sqlar;";
name|mode|mtime|sz|data
B.txt|33188|1565939371|8|bbb
BBB

C.txt|33188|1565939371|8|ccc
CCC

D/DD|16877|1565939371|0|
D/DD/DDD.txt|33188|1565939371|8|ddd
DDD

 Dを消してもその配下であるD/DD, D/DD/DDD.txtが残っている。期待値としてはD配下にあるものはすべて削除して欲しかった……。

 もしやこれの実装が大変だから削除コマンドがないのかな?

だれかの親であればレコードがなくても展開される

 親ディレクトリのレコードを削除した状態で展開してみる。

rm -rf A.txt B.txt C.txt D
sqlite3 texts -Ax
find .
.
./D
./D/DD
./D/DD/DDD.txt
./C.txt
./B.txt
./texts
./run.sh

 Dディレクトリが生成された。まあ他のファイル名にD/があるから妥当。

ディレクトリ削除の確認(再帰削除されない。親レコードなくても展開される)

他のコマンド引数

引数 概要
-f ファイルパス 指定したファイルパスをアーカイブとして使う
-a ファイルパス -fと同様だが、追記モード。appendvfs.c
-C ディレクトリ 相対パスの基準を指定したディレクトリパスに設定する
-n アーカイブ操作するために実行するSQL文を表示する
-- 後続の語はすべてコマンド引数とする。

 べつに使わなくていいかな。

関連情報

圧縮されてない

select sqlar_compress('AAA');
AAA

入力Xが圧縮できない場合、Xのコピーが返されます

 圧縮できてないのでは? SQLITE_HAVE_ZLIBコンパイルオプションが必要だったのでは?

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux

前回まで