SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

SQLiteで組み込みDB体験(2007年版)

組み込みDB:SQLiteをVisual C++ 2005 Express Edition で使う

  • X ポスト
  • このエントリーをはてなブックマークに追加

step-3:日本語対応のためのコード追加

 SQLiteがサポートする文字コードはUTF-8とUTF-16です。上記サンプル「sample.cpp」は、SQLiteのUTF-8版インターフェイス(関数)を呼び出しています。テーブル名やカラム名、各レコード内の文字列がすべてASCIIコードなのでUTF-8版を使っても問題なく動作します(ASCIIはUTFのサブセットですから)。

 日本語のテーブル名/カラム名/文字列を使いたいとなれば、UTF-16すなわちUnicode、char*ではなくwchar_t*を引数/返値とするUTF-16版インターフェイスを呼び出すことになります(SQLiteのワイド文字列インターフェイスではwchar_t*ではなくvoid*になっています)。

 例えば上記サンプルで用いたSQLiteのUTF-8版ライブラリ関数sqlite3_opensqlite3_preparesqlite3_bind_textなどなどにはそれぞれUTF-16版であるsqlite3_open16sqlite3_prepare16sqlite3_bind_text16が用意されています。

 ところが、SQLを実行する最も簡単でお手軽な関数sqlite3_execには対応するUTF-16版関数sqlite3_exec16がないのです。

 ですが、sqlite3_execの実装を読んでみたところ、コードをそのままコピーし数箇所の修正を加えることでUTF-16版sqlite3_exec16が作れることが分かりました。

 まず、「sqlite3.h」の165行目あたりに以下の宣言を書き加えます。

sqlite3_exec16のプロトタイプ宣言
typedef int (*sqlite3_callback16)(void*,int,__wchar_t**, __wchar_t**);

int sqlite3_exec16(
  sqlite3*,                     /* An open database */
  const __wchar_t *sql,         /* SQL to be executed */
  sqlite3_callback16,           /* Callback function */
  void *,                       /* 1st argument to callback function */
  __wchar_t **errmsg            /* Error msg written here */
);

 次に「sqlite3.c」の48524行目(legacy.cの次)に以下の実装を追加します。

sqlite3_exec16の実装
/********** Begin file legacy16.c ***********************************/

typedef int (*sqlite3_callback16)(void*,int,__wchar_t**, __wchar_t**);

int sqlite3_exec16(
  sqlite3 *db,                  /* The database on which the SQL executes */
  const __wchar_t *zSql,        /* The SQL to be executed */
  sqlite3_callback16 xCallback, /* Invoke this callback routine */
  void *pArg,                   /* First argument to xCallback() */
  __wchar_t **pzErrMsg          /* Write error messages here */
){
  int rc = SQLITE_OK;
  const __wchar_t *zLeftover;
  sqlite3_stmt *pStmt = 0;
  __wchar_t **azCols = 0;

  int nRetry = 0;
  int nChange = 0;
  int nCallback;

  if( zSql==0 ) return SQLITE_OK;
  while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) 
          && zSql[0] ){
    int nCol;
    __wchar_t **azVals = 0;

    pStmt = 0;
    rc = sqlite3_prepare16(db, zSql, -1, &pStmt, &zLeftover);
    assert( rc==SQLITE_OK || pStmt==0 );
    if( rc!=SQLITE_OK ){
      continue;
    }
    if( !pStmt ){
      /* this happens for a comment or white-space */
      zSql = zLeftover;
      continue;
    }

    db->nChange += nChange;
    nCallback = 0;

    nCol = sqlite3_column_count(pStmt);
    azCols = sqliteMalloc(2*nCol*sizeof(const __wchar_t *) + 1);
    if( azCols==0 ){
      goto exec_out;
    }

    while( 1 ){
      int i;
      rc = sqlite3_step(pStmt);

      /* Invoke the callback function if required */
      if( xCallback && (SQLITE_ROW==rc ||
          (SQLITE_DONE==rc 
           && !nCallback 
           && db->flags&SQLITE_NullCallback)) ){
        if( 0==nCallback ){
          for(i=0; i<nCol; i++){
            azCols[i] = (__wchar_t*)sqlite3_column_name16(pStmt, i);
          }
          nCallback++;
        }
        if( rc==SQLITE_ROW ){
          azVals = &azCols[nCol];
          for(i=0; i<nCol; i++){
            azVals[i] = (__wchar_t*)sqlite3_column_text16(pStmt, i);
          }
        }
        if( xCallback(pArg, nCol, azVals, azCols) ){
          rc = SQLITE_ABORT;
          goto exec_out;
        }
      }

      if( rc!=SQLITE_ROW ){
        rc = sqlite3_finalize(pStmt);
        pStmt = 0;
        if( db->pVdbe==0 ){
          nChange = db->nChange;
        }
        if( rc!=SQLITE_SCHEMA ){
          nRetry = 0;
          zSql = zLeftover;
          while( iswspace((wint_t)zSql[0]) ) zSql++;
        }
        break;
      }
    }

    sqliteFree(azCols);
    azCols = 0;
  }

exec_out:
  if( pStmt ) sqlite3_finalize(pStmt);
  if( azCols ) sqliteFree(azCols);

  rc = sqlite3ApiExit(0, rc);
  if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
    *pzErrMsg
     = malloc(wcslen((const __wchar_t*)sqlite3_errmsg16(db)+1)
                                                  *sizeof(__wchar_t));
    if( *pzErrMsg ){
      wcscpy(*pzErrMsg, sqlite3_errmsg16(db));
    }
  }else if( pzErrMsg ){
    *pzErrMsg = 0;
  }

  return rc;
}
/********* End of legacy16.c ****************************************/

次のページ
step-4:Unicode版サンプル

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1252 2007/05/07 08:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング