PostgreSQL Advent Calener 2o14 
埋め込みSQL から 
JSONB を扱う 
ぬこ@横浜(@nuko_yokohama)
みなさん、こんにちは 
このスライドは 
PostgreSQL Advent Calender 2014 
7 日目のエントリ用のスライドです。
先日(12/5) 開催された 
PostgreSQLカンファレンスで 
JSONB 型について発表しましたが、 
(スライドはこちら) 
その発表から削った小ネタを 
Advent Calender に転用しますw
ということで今日は 
埋め込みSQL で 
JSONB を使うという 
相変わらずの誰得なネタ 
でいきます。
ところで、皆さん 
埋め込みSQL って 
使ってますか?
というか 
埋め込みSQL って 
なんぞ?
埋め込みSQL 
(Embedded SQL) 
手続き型言語にSQL を埋め込んで 
データベースアクセスを可能にする手法 
(http://ja.wikipedia.org/wiki/%E5%9F%8B%E3%82%81%E8%BE%BC%E3%81%BFSQL)
C 言語の埋め込みSQL 例 
( TRUNCATE TABLE の実行) 
[nuko@localhost ecpg]$ cat sample.pgc 
#include <stdio.h> 
#include <stdlib.h> 
int 
main (void) 
{ 
EXEC SQL CONNECT TO test USER nuko; 
/* TRUNCATE TABLE sample */ 
EXEC SQL BEGIN TRANSACTION; 
EXEC SQL TRUNCATE test; 
EXEC SQL COMMIT; 
EXEC SQL DISCONNECT; 
return (0); 
} 
[nuko@localhost ecpg]$ 
"EXEC SQL“ で 
始まる行は埋め込みSQL として 
SQL そのものを記述できる
当たり前だけど、このファイル 
をC コンパイラにかけても 
エラーになってしまう。
なので、埋め込みSQL は 
コンパイラにかける前に 
「プリコンパイラ」にかけて 
埋め込みSQL を 
変換する必要がある。
PostgreSQL には、埋め込み 
SQL を処理するプリコンパイ 
ラ「ecpg 」がコア機能として 
組み込まれている。 
(http://www.postgresql.jp/document/9.3/html/ecpg.html)
埋め込みSQL を組み込んだ 
C 言語を実行可能にするまでの 
おおまかな手順
イメージ図 
pgcファイル 
ecpg 
Ecpg用 
ヘッダファイル 
cファイル 
cヘッダファイル 
Cコンパイラ 
(gccなど) 
実行形式 
ファイル 
ecpg 
ライブラリ
ということで、 
埋め込みSQL の 
簡単な実例を見てみる。
先ほどの sample.pgc を 
ecpg にかけると 
sample.c ファイルが 
生成される 
$ ls sample* 
sample.pgc 
$ ecpg sample.pgc 
$ ls sample* 
sample.c sample.pgc 
$
生成された” .c” ファイルを 
覗いてみる
こんな感じのC コードに展開$ cat sample.c 
/* Processed by ecpg (4.10.0) */ 
/* These include files are added by the preprocessor */ 
#include <ecpglib.h> 
#include <ecpgerrno.h> 
#include <sqlca.h> 
/* End of automatic include section */ 
#line 1 "sample.pgc" 
#include <stdio.h> 
#include <stdlib.h> 
int 
main (void) 
{ 
{ ECPGconnect(__LINE__, 0, "test" , "nuko" , NULL , NULL, 0); } 
#line 7 "sample.pgc" 
/* TRUNCATE TABLE sample */ 
{ ECPGtrans(__LINE__, NULL, "begin transaction");} 
#line 10 "sample.pgc" 
{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "truncate test", 
ECPGt_EOIT, ECPGt_EORT);} 
#line 11 "sample.pgc" 
(中略) 
return (0); 
}
生成されたC ソースを 
直接変更する必要性はない。 
こんなC ソースが 
裏で生成されてることを 
知っておくくらいでOK
で、生成されたC ソースを 
C コンパイラにかける。 
ecpg ヘッダファイル格納先を-I で指定 
ecpg ライブラリ(libecpg) をリンク時に指定 
$ cc -o sample -I${HOME}/pgsql/include -L${HOME}/pgsql/lib -lecpg sample.c 
$ 
これで完成!
で、埋め込みSQL の 
メリットって何なの?
PostgreSQL 文書を見ると 
一応、以下のメリットが 
あるらしい。
その1 
SQL 標準である。 
へぇー(棒)
埋め込みSQL の概念は 
かなり古くからSQL 標準とし 
て取り込まれている。 
SQL86, SQL89, SQL92 など
PostgreSQL でも 
埋め込みSQL 対応は 
かなり古く(6.3) から 
取り込まれている。
PostgreSQL における 
埋め込みSQL の扱い( 適当) 
西暦PostgreSQL 
バージョン 
PostgreSQL 
での対応 
世界の動き 
1998 年6.3 ecpg の初リリースアントニオ猪木がドン・フ 
ライと引退試合 
2000 年7.0 メモリリーク対応PlayStation2 発売 
2002 年7.2 EXECUTE 文対応 
配列対応の改善 
Xbox 日本国内で発売 
2003 年7.4 ecpg とecpglib のスレッ 
ドセーフ化 
新幹線100 系が運行終了 
2005 年8.0 SET DESCRIPTOR 対応愛知万博 
8.1 x16進数エスケープのサ 
ポート
PostgreSQL における 
埋め込みSQL の扱い( 適当) 
西暦PostgreSQL 
バージョン 
PostgreSQL 
での対応 
世界の動き 
2006年8.2 SHOWコマンド対応 
リグレッション試験対応 
冥王星が惑星から除外 
2008年8.3 V3 Frontend/backend 
protocolの採用 
0系新幹線運用終了 
2009年8.4 ecpgパーサがサーバパー 
サから自動生成 
1兆ジンバブエ・ドルの発行 
2010年9.0 SQLDAサポートはやぶさ、地球に帰還 
2011年9.1 WHERE CURRENT OF 句 
の改善 
おせち事件 
2014年9.4 Cスタイルコメントのネスト対 
応(?) 
WindowsXPおわた 
※ 要は最近も開発継続中ということ。
SQL 標準ってことは 
他DBMS でも 
使われているってこと?
SQL 標準における 
埋め込みSQL の扱い 
SQL標準対応言語 
SQL86 COBOL 
FORTRAN 
PL/I 
SQL89 C 
結構昔から存在している規格
他DBMS での対応 
DBMS COBOL C C++ FORTRAN Pascal 
Oracle ○ ○ ○ ○ ○ 
PostgreSQL ○ △ 
DB2 ○ 
SQLServer 
○ 
(以前) 
Informix ○ 
Oracle はマメにサポートしてるなあ。 
PostgreSQL のC++ 対応は不完全
Oracle もPostgreSQL も 
C 言語の埋め込みSQL を 
サポートしている!
つまり、Oracle のPro*C で 
作ったアプリケーションは 
PostgreSQL ecpg への移植が容易?              _   __ 
             /´=: ミ´二. ヾ\ 
            / ' / '´r ー= 、ヽ. ヽ 、ヽ 
          i / 〃, イ|    | |_L|  l l      埋め込みSQLは誰でもウェルカム 
            |.l.l ル'__ リヽ  ヘl_N ヽ!.l |      PostgreSQLでもOracleでもお好きなものを 
          | |. バ ̄o`   ´o ̄,"|l |       どうぞお気になさらず 
.            レ1  ̄ 〈|:   ̄  !`|       ご自由にお楽しみください 
            ド」 、ー-----‐ ァ ,l イ! 
      _,,... -‐| l ト、` ¨二¨´ ,. イ.l l ー-  ...._ 
   , ィ''"´:::::::::::::::| l.l :::: ヽ、__, .::´ :l.l |::::::::::::::::: ` ¨l ヽ               r'つ 
.   /:::|:::::::::::::::::::::::W \ ::::::::::: /l ル:::::::::::::::::::::::|::: ヽ               /  ∟、-‐''つ 
  /:::::: |::::::::::::::::::::::::l.   \ /  .l::::::::::::::::::::::::|:::::: ヽ         ,.<    )ヽヾニニ⊃ 
. /:::::::::::|:::::::::::::::::::::::::l   /\  .l::::::::::::::::::::::::|:::::::::: ヽ      /\\   i  l ニ二⊇ 
/:::::::::::::::|:::::::::::::::::::::::::l/\_/\.!::::::::::::::::::::::::|:::::::::::::: ヽ    /::::::::::::\. ゝ-─'ー-- ' 
:::::::::::::::::::|::::::::::::::::::::::::: l  ハ   /:::::::::::::::::::::::::|:::::::::::::::::: \ /::::::::::::::::::::/ 
:::::::::::::::::: l:::::::::::::::::::::::::::! ./  ヽ ./::::::::::::::::::::::::::|::::::::::::::::::::/::::::::::::::::::::/ 
ヽ::::::::::::::; イ:::::::::::::::::::::::::::V    V:::::::::::::::::::::::::::: ト、:::::::::::::/::::::::::::::::::::::/ 
:::::::::::::::/  |:::::::::::::::::::::::::::: ヽ ./::::::::::::::::::::::::::::::|  ヽ::::::::::::::::::::::::::::/ 
::::::::::::/   | :::::::::::::::::::::::::::::∨::::::::::::::::::::::::::::::::|    ヽ::::::::::::::::::/ 
_:/   |:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::|     \_:/
そんなに甘くはない。 
              ,  -‐; z ..__      _丿 
        / ゙̄ヽ′ ニ‐ - 、\  \   ところがどっこい 
       Z ´// , ヘ.∧ ヽ \ヽ ゝ   ヽ   ‥‥‥‥ 
       /, / , リ   v ヘ lヽ\ヽヽ.|     ノ  夢じゃありません 
       / イル_- 、ij~   ハにヽ,,\`|  <      ‥‥‥‥! 
.         N⌒ヽヽ // ̄リ:| l l |    ` ) 
            ト、_e. 〉u ' e _ ノノ |.l l |   ∠.    現実です 
          | 、< 、 ij  _,¨ 、イ|| ト、|     ヽ      ‥‥‥! 
.            | ドエエエ「-┴''´|.|L八   ノ - 、   これが現実‥! 
            l. ヒ_ー-r-ー'スソ | l トゝ、.__    | ,. - 、 
    _,,.  -‐ ''" トヽエエエエ! ゝ'´. イ i l;;;;:::::::::::`:: ー/ 
   ハ:::::::::::::::::::::| l\ー一_v~'´ j  ,1;;;;;;::::::::::::::::::: 
.   /:::;l::::::::::::::::::::;W1;;;下、 /l ル' !;;;;;;;;;:::::::::::::::: 
  /:::::;;; l :::::::::::::::::;;;;;;;;;;;;;;;|: : X : : : : : |;;;;;;;;;;;;;;:::::::::::: 
 /:::::;;;;;;|:::::::::::::::;;;;;;;;;;;;;;;;|/: : > 、: : :|;;;;;;;;;;;;;;;::::::::::: 
Oracle 独自拡張多すぎぃ! 
(動的SQL の扱いなど)
【閑話休題 昔話】 
そういえば某社の入社直後に 
プリコンパイラの概念も知らず 
ホスト言語のCOBOL も知らず 
移植元のPL/I ベースの言語も 
知らないままに、 
C 言語でプリコンパイラ作成の一部を 
やらされたのは良い思い出
その2 
プリコンパイル時に 
SQL の構文チェックを 
してくれる。
プリコンパイル時の構文チェックの例 
$ cat sample.pgc 
#include <stdio.h> 
#include <stdlib.h> 
int 
main (void) 
{ 
EXEC SQL CONNECT TO test USER nuko; 
/* TRUNCATE TABLE sample */ 
EXEC SQL BEGIN TRANSACTION; 
EXEC SQL TRANCATE test; 
EXEC SQL COMMIT; 
EXEC SQL DISCONNECT; 
return (0); 
} 
TRUNCATE 文の 
スペルミス 
プリコンパイル時に 
エラーチェックしてくれる 
$ ecpg sample.pgc 
sample.pgc:11: ERROR: unrecognized data type name "TRANCATE" 
$
存在しないテーブル等の 
プリコンパイル時の 
チェックはできない。 
また動的なSQL を使う場合も 
プリコンパイル時の 
チェックはできない。
その3 
ホスト変数による 
プログラム言語への 
情報の授受が簡単?
ということで、ここから 
ホスト変数を使って 
JSONB 型の挿入と 
検索を行なう例を説明します。 
やっと本題ですw
というか 
ホスト変数って 
何よ?
ホスト変数とは、 
C プログラムと 
SQL 文との間で 
データをやり取りするための 
変数のこと。 
DECLARE SECTION で記述
JSONB アクセス用のホスト変数 
ecpg でJSONB を扱う場合はVARCHAR を使うことになる。 
int 
main (void) 
{ 
EXEC SQL BEGIN DECLARE SECTION; 
// Host variable 
VARCHAR insert_data[1024]; 
VARCHAR id[16]; 
VARCHAR name[128]; 
VARCHAR age[16]; 
// null indicator 
int age_ind; 
EXEC SQL END DECLARE SECTION; 
int i; 
可変長テキストの場合は 
VARCHAR という 
特殊な記法で宣言する 
識別子用変数(後述) 
これはホスト変数じゃない
ホスト変数を使ってJSONB をINSERT 
char* values[3] = { 
"{"id":1, "name": {"first": "Oleg"}, "distribute": 
["GIN", "hstore", "json", "jsonb"]}", 
"{"id":2, "age": 59, "name": 
{"last": "Lane", "first": "Tom"}}", 
"{"id":3, "name": {"nickname": "nuko"}, "distribute": ["ksj", 
"neo4jfdw"]}" 
}; 
(中略) 
VARCHAR insert_data[1024]; 
(中略) 
for (i=0; i<=2; i++) { 
insert_data.len = strlen(values[i]); 
strcpy(insert_data.arr, values[i]); 
EXEC SQL INSERT INTO jsonb_t VALUES ( :insert_data ); 
} 
長さ(len) と 
データ実体(arr) を 
事前にセットする 
SQL 内でホスト変数を 
使うときには 
”:” を前につける
ホスト変数を使ってJSONB をSELECT 
(カーソルの細かい説明は割愛。すいません) 
/* select jsonb data (use cursor) */ 
EXEC SQL DECLARE cur CURSOR FOR 
SELECT data->>'id', data->>'name', data->>'age' FROM jsonb_t; 
EXEC SQL OPEN cur; 
while (true) { 
EXEC SQL FETCH NEXT FROM cur INTO :id, :name, :age:age_ind; 
if (sqlca.sqlcode > 0) 
break; 
if ( age_ind < 0) { 
// "age" is null 
printf("id=%s, name=%sn", id.arr, name.arr); 
} else { 
// "age" is not null 
printf("id=%s, name=%s, age=%sn", id.arr, name.arr, age.arr); 
} 
} 
EXEC SQL CLOSE cur; 
JSONB 演算子を使った 
SELECT 文でカーソルを定義 
FETCH 文内に 
ホスト変数を記述 
指示子はホスト変数の 
後ろに記述する 
値参照時には 
arr をつける
/* select jsonb data (use cursor) */ 
EXEC SQL DECLARE cur CURSOR FOR 
SELECT data->>'id', data->>'name', data->>'age' FROM jsonb_t; 
EXEC SQL OPEN cur; 
while (true) { 
EXEC SQL FETCH NEXT FROM cur INTO :id, :name, :age:age_ind; 
if (sqlca.sqlcode > 0) 
break; 
if ( age_ind < 0) { 
// "age" is null 
printf("id=%s, name=%sn", id.arr, name.arr); 
} else { 
// "age" is not null 
printf("id=%s, name=%s, age=%sn", id.arr, name.arr, age.arr); 
} 
} 
EXEC SQL CLOSE cur; 
指示子について 
(主にnull の判別のために使う変数) 
指示子変数が負の値なら 
null である指示子はホスト変数の 
後ろに記述する
プリコンパイル・コンパイル・実行 
$ ecpg jsonb.pgc 
$ cc -o jsonb -I${HOME}/pgsql/include -L${HOME}/pgsql/lib -lecpg jsonb.c 
$ ./jsonb 
id=1, name={"first": "Oleg"} 
id=2, name={"last": "Lane", "first": "Tom"}, age=59 
id=3, name={"nickname": "nuko"} 
$ 
埋め込みSQL でもJSONB は 
フツーに使えました!
ということで、レガシーな 
埋め込みSQL という 
フレームワークでも 
最新機能であるJSONB が 
使えますよ、という話でした。
ecpg 自体、それなりに 
メリットがあるかもしれないが 
いまどき、あえて 
新規アプリケーションを 
ecpg で組む理由は 
あまりない気がする・・・が。
でも、そんな機能でも 
「SQL 標準である」 
「互換性を重視する」 
という理由でサポートしてる 
PostgreSQL は可愛いなあと 
PostgreSQL is lovely...
おしまい

Postgresql advent calender 2014 using jsonb by ecpg

  • 1.
    PostgreSQL Advent Calener2o14 埋め込みSQL から JSONB を扱う ぬこ@横浜(@nuko_yokohama)
  • 2.
    みなさん、こんにちは このスライドは PostgreSQLAdvent Calender 2014 7 日目のエントリ用のスライドです。
  • 3.
    先日(12/5) 開催された PostgreSQLカンファレンスで JSONB 型について発表しましたが、 (スライドはこちら) その発表から削った小ネタを Advent Calender に転用しますw
  • 4.
    ということで今日は 埋め込みSQL で JSONB を使うという 相変わらずの誰得なネタ でいきます。
  • 5.
  • 6.
  • 7.
    埋め込みSQL (Embedded SQL) 手続き型言語にSQL を埋め込んで データベースアクセスを可能にする手法 (http://ja.wikipedia.org/wiki/%E5%9F%8B%E3%82%81%E8%BE%BC%E3%81%BFSQL)
  • 8.
    C 言語の埋め込みSQL 例 ( TRUNCATE TABLE の実行) [nuko@localhost ecpg]$ cat sample.pgc #include <stdio.h> #include <stdlib.h> int main (void) { EXEC SQL CONNECT TO test USER nuko; /* TRUNCATE TABLE sample */ EXEC SQL BEGIN TRANSACTION; EXEC SQL TRUNCATE test; EXEC SQL COMMIT; EXEC SQL DISCONNECT; return (0); } [nuko@localhost ecpg]$ "EXEC SQL“ で 始まる行は埋め込みSQL として SQL そのものを記述できる
  • 9.
  • 10.
    なので、埋め込みSQL は コンパイラにかける前に 「プリコンパイラ」にかけて 埋め込みSQL を 変換する必要がある。
  • 11.
    PostgreSQL には、埋め込み SQLを処理するプリコンパイ ラ「ecpg 」がコア機能として 組み込まれている。 (http://www.postgresql.jp/document/9.3/html/ecpg.html)
  • 12.
    埋め込みSQL を組み込んだ C言語を実行可能にするまでの おおまかな手順
  • 13.
    イメージ図 pgcファイル ecpg Ecpg用 ヘッダファイル cファイル cヘッダファイル Cコンパイラ (gccなど) 実行形式 ファイル ecpg ライブラリ
  • 14.
    ということで、 埋め込みSQL の 簡単な実例を見てみる。
  • 15.
    先ほどの sample.pgc を ecpg にかけると sample.c ファイルが 生成される $ ls sample* sample.pgc $ ecpg sample.pgc $ ls sample* sample.c sample.pgc $
  • 16.
  • 17.
    こんな感じのC コードに展開$ catsample.c /* Processed by ecpg (4.10.0) */ /* These include files are added by the preprocessor */ #include <ecpglib.h> #include <ecpgerrno.h> #include <sqlca.h> /* End of automatic include section */ #line 1 "sample.pgc" #include <stdio.h> #include <stdlib.h> int main (void) { { ECPGconnect(__LINE__, 0, "test" , "nuko" , NULL , NULL, 0); } #line 7 "sample.pgc" /* TRUNCATE TABLE sample */ { ECPGtrans(__LINE__, NULL, "begin transaction");} #line 10 "sample.pgc" { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "truncate test", ECPGt_EOIT, ECPGt_EORT);} #line 11 "sample.pgc" (中略) return (0); }
  • 18.
    生成されたC ソースを 直接変更する必要性はない。 こんなC ソースが 裏で生成されてることを 知っておくくらいでOK
  • 19.
    で、生成されたC ソースを Cコンパイラにかける。 ecpg ヘッダファイル格納先を-I で指定 ecpg ライブラリ(libecpg) をリンク時に指定 $ cc -o sample -I${HOME}/pgsql/include -L${HOME}/pgsql/lib -lecpg sample.c $ これで完成!
  • 20.
  • 21.
  • 22.
  • 23.
    埋め込みSQL の概念は かなり古くからSQL標準とし て取り込まれている。 SQL86, SQL89, SQL92 など
  • 24.
    PostgreSQL でも 埋め込みSQL対応は かなり古く(6.3) から 取り込まれている。
  • 25.
    PostgreSQL における 埋め込みSQLの扱い( 適当) 西暦PostgreSQL バージョン PostgreSQL での対応 世界の動き 1998 年6.3 ecpg の初リリースアントニオ猪木がドン・フ ライと引退試合 2000 年7.0 メモリリーク対応PlayStation2 発売 2002 年7.2 EXECUTE 文対応 配列対応の改善 Xbox 日本国内で発売 2003 年7.4 ecpg とecpglib のスレッ ドセーフ化 新幹線100 系が運行終了 2005 年8.0 SET DESCRIPTOR 対応愛知万博 8.1 x16進数エスケープのサ ポート
  • 26.
    PostgreSQL における 埋め込みSQLの扱い( 適当) 西暦PostgreSQL バージョン PostgreSQL での対応 世界の動き 2006年8.2 SHOWコマンド対応 リグレッション試験対応 冥王星が惑星から除外 2008年8.3 V3 Frontend/backend protocolの採用 0系新幹線運用終了 2009年8.4 ecpgパーサがサーバパー サから自動生成 1兆ジンバブエ・ドルの発行 2010年9.0 SQLDAサポートはやぶさ、地球に帰還 2011年9.1 WHERE CURRENT OF 句 の改善 おせち事件 2014年9.4 Cスタイルコメントのネスト対 応(?) WindowsXPおわた ※ 要は最近も開発継続中ということ。
  • 27.
    SQL 標準ってことは 他DBMSでも 使われているってこと?
  • 28.
    SQL 標準における 埋め込みSQLの扱い SQL標準対応言語 SQL86 COBOL FORTRAN PL/I SQL89 C 結構昔から存在している規格
  • 29.
    他DBMS での対応 DBMSCOBOL C C++ FORTRAN Pascal Oracle ○ ○ ○ ○ ○ PostgreSQL ○ △ DB2 ○ SQLServer ○ (以前) Informix ○ Oracle はマメにサポートしてるなあ。 PostgreSQL のC++ 対応は不完全
  • 30.
    Oracle もPostgreSQL も C 言語の埋め込みSQL を サポートしている!
  • 31.
    つまり、Oracle のPro*C で 作ったアプリケーションは PostgreSQL ecpg への移植が容易?              _   __              /´=: ミ´二. ヾ\             / ' / '´r ー= 、ヽ. ヽ 、ヽ           i / 〃, イ|    | |_L|  l l      埋め込みSQLは誰でもウェルカム             |.l.l ル'__ リヽ  ヘl_N ヽ!.l |      PostgreSQLでもOracleでもお好きなものを           | |. バ ̄o`   ´o ̄,"|l |       どうぞお気になさらず .            レ1  ̄ 〈|:   ̄  !`|       ご自由にお楽しみください             ド」 、ー-----‐ ァ ,l イ!       _,,... -‐| l ト、` ¨二¨´ ,. イ.l l ー-  ...._    , ィ''"´:::::::::::::::| l.l :::: ヽ、__, .::´ :l.l |::::::::::::::::: ` ¨l ヽ               r'つ .   /:::|:::::::::::::::::::::::W \ ::::::::::: /l ル:::::::::::::::::::::::|::: ヽ               /  ∟、-‐''つ   /:::::: |::::::::::::::::::::::::l.   \ /  .l::::::::::::::::::::::::|:::::: ヽ         ,.<    )ヽヾニニ⊃ . /:::::::::::|:::::::::::::::::::::::::l   /\  .l::::::::::::::::::::::::|:::::::::: ヽ      /\\   i  l ニ二⊇ /:::::::::::::::|:::::::::::::::::::::::::l/\_/\.!::::::::::::::::::::::::|:::::::::::::: ヽ    /::::::::::::\. ゝ-─'ー-- ' :::::::::::::::::::|::::::::::::::::::::::::: l  ハ   /:::::::::::::::::::::::::|:::::::::::::::::: \ /::::::::::::::::::::/ :::::::::::::::::: l:::::::::::::::::::::::::::! ./  ヽ ./::::::::::::::::::::::::::|::::::::::::::::::::/::::::::::::::::::::/ ヽ::::::::::::::; イ:::::::::::::::::::::::::::V    V:::::::::::::::::::::::::::: ト、:::::::::::::/::::::::::::::::::::::/ :::::::::::::::/  |:::::::::::::::::::::::::::: ヽ ./::::::::::::::::::::::::::::::|  ヽ::::::::::::::::::::::::::::/ ::::::::::::/   | :::::::::::::::::::::::::::::∨::::::::::::::::::::::::::::::::|    ヽ::::::::::::::::::/ _:/   |:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::|     \_:/
  • 32.
    そんなに甘くはない。              ,  -‐; z ..__      _丿         / ゙̄ヽ′ ニ‐ - 、\  \   ところがどっこい        Z ´// , ヘ.∧ ヽ \ヽ ゝ   ヽ   ‥‥‥‥        /, / , リ   v ヘ lヽ\ヽヽ.|     ノ  夢じゃありません        / イル_- 、ij~   ハにヽ,,\`|  <      ‥‥‥‥! .         N⌒ヽヽ // ̄リ:| l l |    ` )             ト、_e. 〉u ' e _ ノノ |.l l |   ∠.    現実です           | 、< 、 ij  _,¨ 、イ|| ト、|     ヽ      ‥‥‥! .            | ドエエエ「-┴''´|.|L八   ノ - 、   これが現実‥!             l. ヒ_ー-r-ー'スソ | l トゝ、.__    | ,. - 、     _,,.  -‐ ''" トヽエエエエ! ゝ'´. イ i l;;;;:::::::::::`:: ー/    ハ:::::::::::::::::::::| l\ー一_v~'´ j  ,1;;;;;;::::::::::::::::::: .   /:::;l::::::::::::::::::::;W1;;;下、 /l ル' !;;;;;;;;;::::::::::::::::   /:::::;;; l :::::::::::::::::;;;;;;;;;;;;;;;|: : X : : : : : |;;;;;;;;;;;;;;::::::::::::  /:::::;;;;;;|:::::::::::::::;;;;;;;;;;;;;;;;|/: : > 、: : :|;;;;;;;;;;;;;;;::::::::::: Oracle 独自拡張多すぎぃ! (動的SQL の扱いなど)
  • 33.
    【閑話休題 昔話】 そういえば某社の入社直後に プリコンパイラの概念も知らず ホスト言語のCOBOL も知らず 移植元のPL/I ベースの言語も 知らないままに、 C 言語でプリコンパイラ作成の一部を やらされたのは良い思い出
  • 34.
    その2 プリコンパイル時に SQLの構文チェックを してくれる。
  • 35.
    プリコンパイル時の構文チェックの例 $ catsample.pgc #include <stdio.h> #include <stdlib.h> int main (void) { EXEC SQL CONNECT TO test USER nuko; /* TRUNCATE TABLE sample */ EXEC SQL BEGIN TRANSACTION; EXEC SQL TRANCATE test; EXEC SQL COMMIT; EXEC SQL DISCONNECT; return (0); } TRUNCATE 文の スペルミス プリコンパイル時に エラーチェックしてくれる $ ecpg sample.pgc sample.pgc:11: ERROR: unrecognized data type name "TRANCATE" $
  • 36.
    存在しないテーブル等の プリコンパイル時の チェックはできない。 また動的なSQL を使う場合も プリコンパイル時の チェックはできない。
  • 37.
  • 38.
    ということで、ここから ホスト変数を使って JSONB型の挿入と 検索を行なう例を説明します。 やっと本題ですw
  • 39.
  • 40.
    ホスト変数とは、 C プログラムと SQL 文との間で データをやり取りするための 変数のこと。 DECLARE SECTION で記述
  • 41.
    JSONB アクセス用のホスト変数 ecpgでJSONB を扱う場合はVARCHAR を使うことになる。 int main (void) { EXEC SQL BEGIN DECLARE SECTION; // Host variable VARCHAR insert_data[1024]; VARCHAR id[16]; VARCHAR name[128]; VARCHAR age[16]; // null indicator int age_ind; EXEC SQL END DECLARE SECTION; int i; 可変長テキストの場合は VARCHAR という 特殊な記法で宣言する 識別子用変数(後述) これはホスト変数じゃない
  • 42.
    ホスト変数を使ってJSONB をINSERT char*values[3] = { "{"id":1, "name": {"first": "Oleg"}, "distribute": ["GIN", "hstore", "json", "jsonb"]}", "{"id":2, "age": 59, "name": {"last": "Lane", "first": "Tom"}}", "{"id":3, "name": {"nickname": "nuko"}, "distribute": ["ksj", "neo4jfdw"]}" }; (中略) VARCHAR insert_data[1024]; (中略) for (i=0; i<=2; i++) { insert_data.len = strlen(values[i]); strcpy(insert_data.arr, values[i]); EXEC SQL INSERT INTO jsonb_t VALUES ( :insert_data ); } 長さ(len) と データ実体(arr) を 事前にセットする SQL 内でホスト変数を 使うときには ”:” を前につける
  • 43.
    ホスト変数を使ってJSONB をSELECT (カーソルの細かい説明は割愛。すいません) /* select jsonb data (use cursor) */ EXEC SQL DECLARE cur CURSOR FOR SELECT data->>'id', data->>'name', data->>'age' FROM jsonb_t; EXEC SQL OPEN cur; while (true) { EXEC SQL FETCH NEXT FROM cur INTO :id, :name, :age:age_ind; if (sqlca.sqlcode > 0) break; if ( age_ind < 0) { // "age" is null printf("id=%s, name=%sn", id.arr, name.arr); } else { // "age" is not null printf("id=%s, name=%s, age=%sn", id.arr, name.arr, age.arr); } } EXEC SQL CLOSE cur; JSONB 演算子を使った SELECT 文でカーソルを定義 FETCH 文内に ホスト変数を記述 指示子はホスト変数の 後ろに記述する 値参照時には arr をつける
  • 44.
    /* select jsonbdata (use cursor) */ EXEC SQL DECLARE cur CURSOR FOR SELECT data->>'id', data->>'name', data->>'age' FROM jsonb_t; EXEC SQL OPEN cur; while (true) { EXEC SQL FETCH NEXT FROM cur INTO :id, :name, :age:age_ind; if (sqlca.sqlcode > 0) break; if ( age_ind < 0) { // "age" is null printf("id=%s, name=%sn", id.arr, name.arr); } else { // "age" is not null printf("id=%s, name=%s, age=%sn", id.arr, name.arr, age.arr); } } EXEC SQL CLOSE cur; 指示子について (主にnull の判別のために使う変数) 指示子変数が負の値なら null である指示子はホスト変数の 後ろに記述する
  • 45.
    プリコンパイル・コンパイル・実行 $ ecpgjsonb.pgc $ cc -o jsonb -I${HOME}/pgsql/include -L${HOME}/pgsql/lib -lecpg jsonb.c $ ./jsonb id=1, name={"first": "Oleg"} id=2, name={"last": "Lane", "first": "Tom"}, age=59 id=3, name={"nickname": "nuko"} $ 埋め込みSQL でもJSONB は フツーに使えました!
  • 46.
    ということで、レガシーな 埋め込みSQL という フレームワークでも 最新機能であるJSONB が 使えますよ、という話でした。
  • 47.
    ecpg 自体、それなりに メリットがあるかもしれないが いまどき、あえて 新規アプリケーションを ecpg で組む理由は あまりない気がする・・・が。
  • 48.
    でも、そんな機能でも 「SQL 標準である」 「互換性を重視する」 という理由でサポートしてる PostgreSQL は可愛いなあと PostgreSQL is lovely...
  • 49.