Objective-C에서 SQLite 사용 예제
1-1. 헤더 추가하기
Objective-C에서 SQLite를 사용하려면, 다음과 같이 헤더 파일을 추가한다. Xcode 프로젝트를 새로 생성한 후, 아무 라이브러리도 추가하지 않은 상태이다.
#import <sqlite3.h>
1-2. SQLite의 객체
SQLite의 사용을 지원하는 객체에는,
데이터베이스 연결 정보를 가지고 있는 sqlite3
와,
SQL 구문을 데이터베이스로 전송하기 전 컴파일을 하는 sqlite3_stmt
객체가 있다. 각 형식을 갖는 두 객체를 선언한다.
// ...
sqlite3 * database; // 데이터베이스 연결정보
sqlite3_stmt * databaseStatement; // 쿼리 구문 컴파일러
//...
1-3. SQLite 데이터베이스의 생성 또는 열기
SQLite 함수는 데이터베이스를 동적으로(소스코드 상으로) 생성과 기존에 존재하는 데이터베이스를 여는 방법을 구분하지 않는다. sqlite3_open
함수에 데이터베이스 파일 경로를 지정했을 때 해당 경로에 실제로 데이터베이스 파일이 있다면 그것을 열고, 존재하지 않으면 새로 생성한다음 이를 연다.
//...
NSString * databasePath = @"./test001.sqlite"; // 새로 생성할 데이터베이스 파일 또는 기존에 존재하는 데이터베이스 파일
sqlite3 * database; // 데이터베이스 연결정보
sqlite3_stmt * databaseStatement; // 쿼리 구문 컴파일러
//...
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(@"SUCCESS: sqlite3_open");
sqlite3_close(database);
database = nil;
}
else
{
NSLog(@"FAILURE: sqlite3_open");
sqlite3_close(database);
database = nil;
}
// ...
실행 결과, 기존 데이터베이스 파일이 없다면 다음과 같이 0바이트 파일이 생성됨을 확인할 수 있다.
1-4. 반환 결과가 없는 SQL 쿼리 실행하기
테이블을 대상으로 하는 CREATE
, DROP
, 레코드를 대상으로 하는 INSERT
, UPDATE
, DELETE
의 명령은 별도의 반환값이 필요하지 않다. SQL을 실행만 하는 방법은 sqlite3_exec
함수를 사용하는 것이다.
SQLITE_API int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
다음은 sqlite3_exec
함수를 사용하여 반환 결과가 없는 쿼리를 실행하는 예이다.
//...
NSString * databasePath = @"./test001.sqlite"; // 새로 생성할 데이터베이스 파일 또는 기존에 존재하는 데이터베이스 파일
sqlite3 * database = nil; // 데이터베이스 연결정보
sqlite3_stmt * databaseStatement = nil; // 쿼리 구문 컴파일러
NSString * databaseQuery = nil; // SQL 구문
char * databaseMessage = nil; // 오류 메시지를 전달받을 포인터 변수
// ...
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(@"SUCCESS: sqlite3_open");
databaseQuery = @"CREATE TABLE IF NOT EXISTS `Table1`(`index` INTEGER PRIMARY KEY, `value` TEXT);";
if (sqlite3_exec(database, [databaseQuery UTF8String], NULL, NULL, &databaseMessage) == SQLITE_OK)
{
NSLog(@"SUCCESS: sqlite3_exec: %@", databaseQuery);
}
else
{
NSLog(@"FAILURE: sqlite3_exec: %s", databaseMessage);
}
databaseQuery = @"INSERT INTO `Table1`(`value`) VALUES ('Hello, World!');";
if (sqlite3_exec(database, [databaseQuery UTF8String], NULL, NULL, &databaseMessage) == SQLITE_OK)
{
NSLog(@"SUCCESS: sqlite3_exec: %@", databaseQuery);
}
else
{
NSLog(@"FAILURE: sqlite3_exec: %s", databaseMessage);
}
sqlite3_close(database);
database = nil;
}
else
{
NSLog(@"FAILURE: sqlite3_open");
sqlite3_close(database);
database = nil;
}
// ...
다음은 위에서 실행한 코드의 결과 생성된 파일을 DB Browser for SQLite로 연 것이다. 테이블과 필드가 정의되어 있는 것을 확인할 수 있다.
또한 INSERT 구문의 실행 결과 레코드가 1개 생성되어 있음을 확인할 수 있다.
1-5. 반환 결과가 있는 SQL 쿼리 실행하기
SELECT
구문은 레코드 집합을 결과로서 반환한다. 이를 실행하여 반환값을 얻기 위해서는 sqlite3_prepare_v2
함수를 사용한다. SQL 쿼리가 UTF-16으로 인코딩 되어 있다면 sqlite3_prepare16_v2
함수를 사용한다. 이 함수의 실행 결과 sqlite3_stmt
형 객체가 얻어지는데 이 객체를 통해 구문분석 및 컴파일된 SQL 쿼리가 보관되므로 잘 보관해 둔다.
SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
); // UTF-8 version.
SQLITE_API int sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
); // UTF-16 version
다음은 sqlite3_prepare_v2
함수와 sqlite3_stmt
객체를 사용하여 SELECT
구문을 수행하는 과정의 예이다.
//...
NSString * databasePath = @"./test001.sqlite"; // 새로 생성할 데이터베이스 파일 또는 기존에 존재하는 데이터베이스 파일
sqlite3 * database = nil; // 데이터베이스 연결정보
sqlite3_stmt * databaseStatement = nil; // 쿼리 구문 컴파일러
NSString * databaseQuery = nil; // SQL 구문
char * databaseMessage = nil; // 오류 메시지를 전달받을 포인터 변수
// ...
databaseQuery = @"SELECT * FROM `Table1`;";
if (sqlite3_prepare_v2(database, [databaseQuery UTF8String], -1, &databaseStatement, nil) == SQLITE_OK)
{
int query_column = 0;
int field_index = 0;
const char * field_value = nil;
query_column = sqlite3_column_count(databaseStatement);
NSLog(@"SUCCESS: sqlite3_prepare_v2: %@, query_column = %d", databaseQuery, query_column);
while (sqlite3_step(databaseStatement) == SQLITE_ROW)
{
field_index = (int) sqlite3_column_int(databaseStatement, 0);
field_value = (const char *) sqlite3_column_text(databaseStatement, 1);
NSLog(@"SUCCESS: sqlite3_step: %d, %s", field_index, field_value);
}
sqlite3_finalize(databaseStatement);
}
else
{
NSLog(@"FAILURE: sqlite3_prepare_v2");
}
다음은 실행 결과이다. 터미널로 출력되는 레코드와 DB Browser for SQLite에서 보여지는 레코드가 일치함을 알 수 있다.
1-6. 텍스트 바인딩
UPDATE SET ...
구문이나 SELECT ... WHERE
구문과 같이 쿼리에 사용자 문자열이 들어가는 경우, 사용자 문자열에 포함된 따옴표 및 기타 문자 의한 구문 오류가 발생할 수 있다. 이를 방지하기 위해 텍스트 바인딩을 사용할 수 있다.
//...
NSString * databasePath = @"./test001.sqlite"; // 새로 생성할 데이터베이스 파일 또는 기존에 존재하는 데이터베이스 파일
sqlite3 * database = nil; // 데이터베이스 연결정보
sqlite3_stmt * databaseStatement = nil; // 쿼리 구문 컴파일러
NSString * databaseQuery = nil; // SQL 구문
char * databaseMessage = nil; // 오류 메시지를 전달받을 포인터 변수
// ...
databaseQuery = @"SELECT * FROM `Table1` WHERE (`index` = ? AND `value` = ?);";
if (sqlite3_prepare_v2(database, [databaseQuery UTF8String], -1, &databaseStatement, nil) == SQLITE_OK)
{
int query_column = 0;
int field_index = 0;
const char * field_value = nil;
sqlite3_bind_int(databaseStatement, 1, 100); // index = 100인 레코드 중에서...
sqlite3_bind_text(databaseStatement, 2, "foo", -1, nil); // value = "foo"인 레코드들을 찾는다.
query_column = sqlite3_column_count(databaseStatement);
NSLog(@"SUCCESS: sqlite3_prepare_v2: %@, query_column = %d", databaseQuery, query_column);
while (sqlite3_step(databaseStatement) == SQLITE_ROW)
{
field_index = (int) sqlite3_column_int(databaseStatement, 0);
field_value = (const char *) sqlite3_column_text(databaseStatement, 1);
NSLog(@"SUCCESS: sqlite3_step: %d, %s", field_index, field_value);
}
sqlite3_finalize(databaseStatement);
}
else
{
NSLog(@"FAILURE: sqlite3_prepare_v2");
}
'Programming Language > Objective-C' 카테고리의 다른 글
이벤트 처리시 멤버에 들어간 배열 접근에서 EXC_BAD_ACCESS 오류가 뜰 경우 (0) | 2014.05.12 |
---|---|
NSDate로 현재 날짜 얻기 (0) | 2012.04.28 |
NSString과 C 문자열간 변환하기 (0) | 2012.02.26 |
Objective-C 첫 예제 (0) | 2012.01.21 |