人々の電話番号と住所をデータベース テーブルに保存しようとしています。複数の電話番号と住所をサポートしたいのですが、国によって形式が異なることを期待しています。その柔軟性を可能にし、特定のフィールドによる効率的なクエリを可能にするために、hstore を使用することにしました。現状では、データベースから値を受け取ることができますが、Java から値を挿入する方法が見つかりませんでした。表(簡略化)は次のようになります。
CREATE TABLE IF NOT EXISTS contacts ( "
+ "id uuid NOT NULL, "
+ "title character varying NOT NULL DEFAULT '', "
+ "first_name character varying NOT NULL, "
+ "last_name character varying NOT NULL, "
+ "phones hstore[] NOT NULL DEFAULT '{}', "
+ "addresses hstore[] NOT NULL DEFAULT '{}')"
値をバインドするカスタム JDBI Binder を作成しましたが、実行しようとしてもステートメントを取得できません。現在、Binder コード スニペットは次のようになっています。
@Override
public void bind(SQLStatement<?> q, BindContactBean bind, ContactBean bean) {
q.bind("phones",
getHstoreArray(q, PhoneDetailMapper.toMapArray(bean.phones.get())));
q.bind("addresses",
getHstoreArray(q, AddressDetailMapper.toMapArray(bean.addresses.get())));
getHstoreArray 関数は、Java 配列を SQL 配列に変換するヘルパーで、次のようになります。
private Array getHstoreArray(SQLStatement<?> q, Map<String, String>[] map) {
try {
return q.getContext().getConnection().createArrayOf("hstore", map);
} catch (SQLException e) {
throw new IllegalArgumentException(e);
}
}
問題はデータのエンコードにあると思います。たとえば、データの場合 (簡単にするために JSON 表記で)
{
"firstName": "Maximum",
"lastName": "Details",
"status": "active",
"phones": [{
"type": "mobile",
"number": "0777 66 55 44"
}]
}
クエリは次のように展開されます。
INSERT INTO contacts (
id, first_name, last_name, status, phones )
VALUES ( '9be1a040-b408-11e3-bb43-00231832fa86', 'Maximum', 'Details', 4,
'{"{type=mobile, extracted_number=extracted, number=07777 66 55 44}"}'
)
PGAdmin の SQL エディターから実行しようとすると、返されるエラーは次のとおりです。
ERROR: Syntax error near 'm' at position 6
LINE 5: '{"{type=mobile, extracted_number=extracted, number=07777 66...
^
********** Error **********
ERROR: Syntax error near 'm' at position 6
SQL state: XX000
Character: 179
hstore[] の代わりに JSON を使用することを検討しましたが、特定のフィールドによるクエリが遅くなり、精度が低下するため (基本的にテキスト検索)、避けたいと思います。hstore の前に試した別のオプションは UDT の配列ですが、単純なタスクのようには見えない PGobject のパーサーを作成しないと、データベースから読み取ることさえできませんでした。
編集
データベース内のデータを見て、次の方法でエスケープしたとき:
'{"\"type\"=>\"mobile\", \"number\"=>\"07777 66 55 44\", \"extracted_number\"=>\"777665544\""}'
SQL エディターから手動でクエリを実行できますが、Java ではまだうまくいきません。