第6回 Cocoa 勉強会(2004/7/10)

SQLite を Cocoa で使う(新居雅行)
SQL データベースの SQLite
SQLite の特徴


Public Dmain 、 オ ー プ ン ソ ー ス で 、 事 実 上 自 由 に 使 え る SQL デ ー タ ベ ー ス
(http://www.sqlite.org/)



オリジナルには C/C++および TCL のインタフェースだけが用意されている



PHP5 への標準バンドル、さらには Mac OS X v10.4 へのバンドルが予定されている



ネットワークには基本的には非対応のため、
組み込み用途が主なものとなる。
データベース
は、1 つのファイルに保存される



「タイプレス」という独特の考え方。フィールドにはタイプを指定しないでもいい(という
か、指定してもあまり意味はないかも)



数値については「精度」
「桁数」的な概念はまったくない。数値は倍精度浮動小数点数(64
ビット)にすべて展開される。



文字も数値もある意味は区別がないためちょっと独特。ただし、そのため BLOB 処理がち
ょっと甘いとも言える



SQL の非サポート機能で目につくのは GRANT がないこと。アクセス権はデータベースフ
ァイルに対して設定するというのが基本コンセプト。また、タイプレスのためか CHECK
制約は機能しないなどもある



Ver.2.8 系列は UTF-8 対応、Ver.3 より UTF-8/16 の両方に対応。なお、Ver.3 ではタイプ
の扱いが違ってくる模様。



MySQL よりも速いといったベンチマークテストを掲載している。
PostgreSQL よりは 10∼
20 倍、MySQL よりも 2 倍速いとしているが、SQLite では 1 つのトランザクションで処理
する事でそのスピードが出る

SQLite を Mac OS X で使うには
バイナリとして配布されているのは、Linux と Windows のみ。そのため、Mac OS X で使うに
はビルドしないといけないが、配布されているソース群には make すらない。Mac OS X で手
軽に使うには、以下のものが必要。
SQLite の Mac OS X 版ビルド
http://www.c-command.com/tools/sqlite.shtml
QuickLite
http://www.webbotech.com/
1
SQLite のコネクティビティ
SQLite の接続機能を強化するものとしては以下のものがある。
SQLite 用の ODBC および JDBC のドライバ
http://www.ch-werner.de/sqliteodbc/ http://www.ch-werner.de/javasqlite/
SQLiteServer 1.0(SQLite をネットワークからアクセス。REALbasic で制作)
http://sqlabs.net/

QuickLite について


SQLite を使うための Cocoa のクラスをオープンソースで提供しているのが QuickLite



確かに、Xcode で開いてデータベース処理はできるが、事実上、自分で SQL 文をテキスト
で作成しなければならない。
つまり、
データベースの内容をオブジェクト化するものではな
く、SQLite へのインタフェースを取るための Cocoa クラス



そのため、以下の 3 種類のオブジェクト(クラス)について知るだけで使える(というか、
その程度の機能)
。以下の表は主なメソッドの紹介で、他にもメソッドがある

NSQuickLiteDatabase
databaseWithFile:
open
close
performQuery:
prepareStringForQuery:
encodeDataToBase64:

NSQuickLiteCursor
rowCount
columnCount
columnNames
rowAtIndex:
valuesForColumn:
valuesForRow:

NSQuickLiteRow
stringForColumn:
dataForColumn: andRow:
values

データベースファイルの抽象化
データベースファイルを指定して初期化
データベースをオープン
データベースをクローズ
文字列で指定した SQL 文を発行、NSQuickLinkCursor
を戻す
SQL 文をクエリーできるように変換。つまりクォートの
置き換え
NSData を base64 にして NSString を戻す
クエリー結果の抽象化クラス
レコード数
フィールド数
フィールド名の NSArray を得る
レコード番号を指定して NSQuickLinkRow への参照を
得る
文字列で指定したフィールドのデータを NSArray で得る
レコード番号で指定したレコードのデータを
NSDictionary で得る
クエリー結果の中の 1 レコードを抽象化するクラス
フィールド名を指定してそのフィールドのデータを文字
列として得る
フィールド名とレコード番号指定してそのフィールドの
データを NSData として得る
レコードのデータを NSDictionary で得る
2


NSString での Unicode でインプット/アプトプットがきちんとできる。もちろん日本語も
OK



BLOB 対応のために base64 でエンコードする。挿入するデータについては自分で base64
にしないといけないが、メソッドは用意されている。取り出しは NSData として取り出す
メソッドで元のバイナリが得られる



SQLite をフレームワークにするというプロジェクトもあるが、激しくバグっており(きっ
と、プロジェクトを作ったけど、ほんとにフレームワークとして使ってはいないだろう)
、
それはそのままでは使えない。動くフレームワークは、Cocoa 勉強会のサーバ領域に保存
(ファイル名: QuickLite Framework.zip)



テキストファイルのインポート機能があることはあるが、
これはちょっと使えない…。
まじ
めにテキストファイルのインポートする人はちゃんと改造するか、自分で作りましょう

QuickLite を使ったサンプルプログラム
ファイル名:msykQLsample.zip
"SQL1" = "INSERT INTO TEST1(str1,str2) VALUES( '表示', 'aaa strings' );";
"SQL2" = "INSERT INTO TEST1(str1,str2) VALUES( '日本語', 'aaa strings' );";
"SQL3" = "INSERT INTO TEST1(str1,str2) VALUES( '東京特許許可局', 'aaa strings' );";
"SQL4" = "INSERT INTO TEST1(str1,str2) VALUES( '髙島屋', 'aaa strings' );";
"SQL5" = "INSERT INTO TEST1(str1,str2) VALUES( '美しい日本語', 'aaa strings' );";
"SQL6" = "INSERT INTO TEST1(str1,str2) VALUES( '日本語', 'aaa strings' );";

3
#import "DBAccess.h"
//フレームワーク化したQuickLiteをインポート
#import <QuickLite/QuickLite.h>
@implementation DBAccess
- (IBAction)testRun:(id)sender
{
long i;
NSString* dbPath = @"~/testdb"; //データベースファイル
QuickLiteDatabase* db = [QuickLiteDatabase databaseWithFile: dbPath];
//データベースファイルをもとにしたデータベースオブジェクトを構築する
[db open];

//データベースを開く

NSArray* tableArray = [db tables];

//テーブルの個数を参照

for (i = 0; i < [tableArray count]; i++)

//とりあえずテーブルをすべて消す

[db dropTable: [tableArray objectAtIndex: i]];
[db performQuery: @"CREATE TABLE TEST1(id INTEGER PRIMARY KEY, str1, str2);"];
//テーブルを作成するクエリーを発行する
[db performQuery: NSLocalizedString( @"SQL1", @"" ) ];

//INSERTのクエリーを発行

[db performQuery: NSLocalizedString( @"SQL2", @"" ) ];
:
[db performQuery: NSLocalizedString( @"SQL9", @"" ) ];
[db performQuery: NSLocalizedString( @"SQL10", @"" ) ];
QuickLiteCursor* cursor = [db performQuery: @"SELECT * FROM TEST1;"];
//テーブルのレコードをすべて取り出す
long rowCount = [cursor rowCount];

//レコード数を求める

if (rowCount > 0) {
for (i = 0; i < rowCount; i++) {

//それぞれのレコードについて

QuickLiteRow* row = [cursor rowAtIndex: i]; //行データを参照し
if (row != nil) {

//各フィールドの値を取り出す

NSLog(@"%@: %@", @"id", [row stringForColumn: @"id"]);
NSLog(@"%@: %@", @"str1", [row stringForColumn: @"str1"]);
NSLog(@"%@: %@", @"str2", [row stringForColumn: @"str2"]);
}
}
}
[db close]; //データベースを閉じる
}
@end

4

Cocoa勉強会#6-SQLiteをCocoaで使う

  • 1.
    第6回 Cocoa 勉強会(2004/7/10) SQLiteを Cocoa で使う(新居雅行) SQL データベースの SQLite SQLite の特徴  Public Dmain 、 オ ー プ ン ソ ー ス で 、 事 実 上 自 由 に 使 え る SQL デ ー タ ベ ー ス (http://www.sqlite.org/)  オリジナルには C/C++および TCL のインタフェースだけが用意されている  PHP5 への標準バンドル、さらには Mac OS X v10.4 へのバンドルが予定されている  ネットワークには基本的には非対応のため、 組み込み用途が主なものとなる。 データベース は、1 つのファイルに保存される  「タイプレス」という独特の考え方。フィールドにはタイプを指定しないでもいい(という か、指定してもあまり意味はないかも)  数値については「精度」 「桁数」的な概念はまったくない。数値は倍精度浮動小数点数(64 ビット)にすべて展開される。  文字も数値もある意味は区別がないためちょっと独特。ただし、そのため BLOB 処理がち ょっと甘いとも言える  SQL の非サポート機能で目につくのは GRANT がないこと。アクセス権はデータベースフ ァイルに対して設定するというのが基本コンセプト。また、タイプレスのためか CHECK 制約は機能しないなどもある  Ver.2.8 系列は UTF-8 対応、Ver.3 より UTF-8/16 の両方に対応。なお、Ver.3 ではタイプ の扱いが違ってくる模様。  MySQL よりも速いといったベンチマークテストを掲載している。 PostgreSQL よりは 10∼ 20 倍、MySQL よりも 2 倍速いとしているが、SQLite では 1 つのトランザクションで処理 する事でそのスピードが出る SQLite を Mac OS X で使うには バイナリとして配布されているのは、Linux と Windows のみ。そのため、Mac OS X で使うに はビルドしないといけないが、配布されているソース群には make すらない。Mac OS X で手 軽に使うには、以下のものが必要。 SQLite の Mac OS X 版ビルド http://www.c-command.com/tools/sqlite.shtml QuickLite http://www.webbotech.com/ 1
  • 2.
    SQLite のコネクティビティ SQLite の接続機能を強化するものとしては以下のものがある。 SQLite用の ODBC および JDBC のドライバ http://www.ch-werner.de/sqliteodbc/ http://www.ch-werner.de/javasqlite/ SQLiteServer 1.0(SQLite をネットワークからアクセス。REALbasic で制作) http://sqlabs.net/ QuickLite について  SQLite を使うための Cocoa のクラスをオープンソースで提供しているのが QuickLite  確かに、Xcode で開いてデータベース処理はできるが、事実上、自分で SQL 文をテキスト で作成しなければならない。 つまり、 データベースの内容をオブジェクト化するものではな く、SQLite へのインタフェースを取るための Cocoa クラス  そのため、以下の 3 種類のオブジェクト(クラス)について知るだけで使える(というか、 その程度の機能) 。以下の表は主なメソッドの紹介で、他にもメソッドがある NSQuickLiteDatabase databaseWithFile: open close performQuery: prepareStringForQuery: encodeDataToBase64: NSQuickLiteCursor rowCount columnCount columnNames rowAtIndex: valuesForColumn: valuesForRow: NSQuickLiteRow stringForColumn: dataForColumn: andRow: values データベースファイルの抽象化 データベースファイルを指定して初期化 データベースをオープン データベースをクローズ 文字列で指定した SQL 文を発行、NSQuickLinkCursor を戻す SQL 文をクエリーできるように変換。つまりクォートの 置き換え NSData を base64 にして NSString を戻す クエリー結果の抽象化クラス レコード数 フィールド数 フィールド名の NSArray を得る レコード番号を指定して NSQuickLinkRow への参照を 得る 文字列で指定したフィールドのデータを NSArray で得る レコード番号で指定したレコードのデータを NSDictionary で得る クエリー結果の中の 1 レコードを抽象化するクラス フィールド名を指定してそのフィールドのデータを文字 列として得る フィールド名とレコード番号指定してそのフィールドの データを NSData として得る レコードのデータを NSDictionary で得る 2
  • 3.
     NSString での Unicodeでインプット/アプトプットがきちんとできる。もちろん日本語も OK  BLOB 対応のために base64 でエンコードする。挿入するデータについては自分で base64 にしないといけないが、メソッドは用意されている。取り出しは NSData として取り出す メソッドで元のバイナリが得られる  SQLite をフレームワークにするというプロジェクトもあるが、激しくバグっており(きっ と、プロジェクトを作ったけど、ほんとにフレームワークとして使ってはいないだろう) 、 それはそのままでは使えない。動くフレームワークは、Cocoa 勉強会のサーバ領域に保存 (ファイル名: QuickLite Framework.zip)  テキストファイルのインポート機能があることはあるが、 これはちょっと使えない…。 まじ めにテキストファイルのインポートする人はちゃんと改造するか、自分で作りましょう QuickLite を使ったサンプルプログラム ファイル名:msykQLsample.zip "SQL1" = "INSERT INTO TEST1(str1,str2) VALUES( '表示', 'aaa strings' );"; "SQL2" = "INSERT INTO TEST1(str1,str2) VALUES( '日本語', 'aaa strings' );"; "SQL3" = "INSERT INTO TEST1(str1,str2) VALUES( '東京特許許可局', 'aaa strings' );"; "SQL4" = "INSERT INTO TEST1(str1,str2) VALUES( '髙島屋', 'aaa strings' );"; "SQL5" = "INSERT INTO TEST1(str1,str2) VALUES( '美しい日本語', 'aaa strings' );"; "SQL6" = "INSERT INTO TEST1(str1,str2) VALUES( '日本語', 'aaa strings' );"; 3
  • 4.
    #import "DBAccess.h" //フレームワーク化したQuickLiteをインポート #import <QuickLite/QuickLite.h> @implementationDBAccess - (IBAction)testRun:(id)sender { long i; NSString* dbPath = @"~/testdb"; //データベースファイル QuickLiteDatabase* db = [QuickLiteDatabase databaseWithFile: dbPath]; //データベースファイルをもとにしたデータベースオブジェクトを構築する [db open]; //データベースを開く NSArray* tableArray = [db tables]; //テーブルの個数を参照 for (i = 0; i < [tableArray count]; i++) //とりあえずテーブルをすべて消す [db dropTable: [tableArray objectAtIndex: i]]; [db performQuery: @"CREATE TABLE TEST1(id INTEGER PRIMARY KEY, str1, str2);"]; //テーブルを作成するクエリーを発行する [db performQuery: NSLocalizedString( @"SQL1", @"" ) ]; //INSERTのクエリーを発行 [db performQuery: NSLocalizedString( @"SQL2", @"" ) ]; : [db performQuery: NSLocalizedString( @"SQL9", @"" ) ]; [db performQuery: NSLocalizedString( @"SQL10", @"" ) ]; QuickLiteCursor* cursor = [db performQuery: @"SELECT * FROM TEST1;"]; //テーブルのレコードをすべて取り出す long rowCount = [cursor rowCount]; //レコード数を求める if (rowCount > 0) { for (i = 0; i < rowCount; i++) { //それぞれのレコードについて QuickLiteRow* row = [cursor rowAtIndex: i]; //行データを参照し if (row != nil) { //各フィールドの値を取り出す NSLog(@"%@: %@", @"id", [row stringForColumn: @"id"]); NSLog(@"%@: %@", @"str1", [row stringForColumn: @"str1"]); NSLog(@"%@: %@", @"str2", [row stringForColumn: @"str2"]); } } } [db close]; //データベースを閉じる } @end 4