/* Copyright (c) 2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Justin Deoliveira (Boundless) - initial implementation
*/
package org.locationtech.geogig.storage.sqlite;
import static org.locationtech.geogig.storage.sqlite.Xerial.log;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import org.locationtech.geogig.api.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sqlite.SQLiteDataSource;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
/**
* Config database based on xerial SQLite jdbc driver.
*
* @author Justin Deoliveira, Boundless
*/
public class XerialConfigDatabase extends SQLiteConfigDatabase {
static final Logger LOG = LoggerFactory.getLogger(XerialConfigDatabase.class);
@Inject
public XerialConfigDatabase(Platform platform) {
super(platform);
}
@Override
protected String get(final Entry entry, Config config) {
return new DbOp<String>() {
@Override
protected String doRun(Connection cx) throws IOException, SQLException {
String sql = "SELECT value FROM config WHERE section = ? AND key = ?";
String s = entry.section;
String k = entry.key;
PreparedStatement ps = open(cx.prepareStatement(log(sql, LOG, s, k)));
ps.setString(1, s);
ps.setString(2, k);
ResultSet rs = open(ps.executeQuery());
return rs.next() ? rs.getString(1) : null;
}
}.run(connect(config));
}
@Override
protected Map<String, String> all(Config config) {
return new DbOp<Map<String, String>>() {
@Override
protected Map<String, String> doRun(Connection cx) throws IOException, SQLException {
String sql = "SELECT section,key,value FROM config";
ResultSet rs = open(open(cx.createStatement()).executeQuery(log(sql, LOG)));
Map<String, String> all = Maps.newLinkedHashMap();
while (rs.next()) {
String entry = String.format("%s.%s", rs.getString(1), rs.getString(2));
all.put(entry, rs.getString(3));
}
return all;
}
}.run(connect(config));
}
@Override
protected Map<String, String> all(final String section, Config config) {
return new DbOp<Map<String, String>>() {
@Override
protected Map<String, String> doRun(Connection cx) throws IOException, SQLException {
String sql = "SELECT section,key,value FROM config WHERE section = ?";
PreparedStatement ps = open(cx.prepareStatement(log(sql, LOG, section)));
ps.setString(1, section);
ResultSet rs = open(ps.executeQuery());
Map<String, String> all = Maps.newLinkedHashMap();
while (rs.next()) {
String entry = String.format("%.%", rs.getString(1), rs.getString(2));
all.put(entry, rs.getString(3));
}
return all;
}
}.run(connect(config));
}
@Override
protected List<String> list(final String section, Config config) {
return new DbOp<List<String>>() {
@Override
protected List<String> doRun(Connection cx) throws IOException, SQLException {
String sql = "SELECT key FROM config WHERE section = ?";
PreparedStatement ps = open(cx.prepareStatement(log(sql, LOG, section)));
ps.setString(1, section);
ResultSet rs = open(ps.executeQuery());
List<String> all = Lists.newArrayList();
while (rs.next()) {
all.add(rs.getString(1));
}
return all;
}
}.run(connect(config));
}
@Override
protected void put(final Entry entry, final String value, Config config) {
new DbOp<Void>() {
@Override
protected boolean isAutoCommit() {
return false;
}
@Override
protected Void doRun(Connection cx) throws IOException, SQLException {
doRemove(entry, cx);
String sql = "INSERT OR REPLACE INTO config (section,key,value) VALUES (?,?,?)";
String s = entry.section;
String k = entry.key;
PreparedStatement ps = open(cx.prepareStatement(log(sql, LOG, s, k, value)));
ps.setString(1, s);
ps.setString(2, k);
ps.setString(3, value);
ps.executeUpdate();
cx.commit();
return null;
}
}.run(connect(config));
}
@Override
protected void remove(final Entry entry, Config config) {
new DbOp<Void>() {
@Override
protected Void doRun(Connection cx) throws IOException, SQLException {
doRemove(entry, cx);
return null;
}
}.run(connect(config));
}
void doRemove(final Entry entry, Connection cx) {
new DbOp<Void>() {
@Override
protected Void doRun(Connection cx) throws IOException, SQLException {
String sql = "DELETE FROM config WHERE section = ? AND key = ?";
String s = entry.section;
String k = entry.key;
PreparedStatement ps = open(cx.prepareStatement(log(sql, LOG, s, k)));
ps.setString(1, s);
ps.setString(2, k);
ps.executeUpdate();
return null;
}
}.run(cx);
}
@Override
protected void removeAll(final String section, Config config) {
new DbOp<Void>() {
@Override
protected Void doRun(Connection cx) throws IOException, SQLException {
String sql = "DELETE FROM config WHERE section = ?";
PreparedStatement ps = open(cx.prepareStatement(log(sql, LOG, section)));
ps.setString(1, section);
ps.executeUpdate();
return null;
}
}.run(connect(config));
}
SQLiteDataSource connect(Config config) {
SQLiteDataSource dataSource = Xerial.newDataSource(config.file);
new DbOp<Void>() {
@Override
protected Void doRun(Connection cx) throws IOException, SQLException {
String sql = "CREATE TABLE IF NOT EXISTS config (section VARCHAR, key VARCHAR, value VARCHAR,"
+ " PRIMARY KEY (section,key))";
Statement st = open(cx.createStatement());
st.execute(log(sql, LOG));
sql = "CREATE INDEX IF NOT EXISTS config_section_idx ON config (section)";
st.execute(log(sql, LOG));
return null;
}
}.run(dataSource);
return dataSource;
}
}