support PostgreSQL >= 9.5 upsert capability

This commit is contained in:
Xavier Léauté 2016-04-01 16:52:47 -07:00
parent 18b9ea62cf
commit 0f8a037bcd
1 changed files with 44 additions and 15 deletions

View File

@ -31,6 +31,7 @@ import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.tweak.HandleCallback; import org.skife.jdbi.v2.tweak.HandleCallback;
import org.skife.jdbi.v2.util.StringMapper; import org.skife.jdbi.v2.util.StringMapper;
import java.sql.DatabaseMetaData;
import java.sql.SQLException; import java.sql.SQLException;
public class PostgreSQLConnector extends SQLMetadataConnector public class PostgreSQLConnector extends SQLMetadataConnector
@ -41,6 +42,8 @@ public class PostgreSQLConnector extends SQLMetadataConnector
private final DBI dbi; private final DBI dbi;
private volatile Boolean canUpsert;
@Inject @Inject
public PostgreSQLConnector(Supplier<MetadataStorageConnectorConfig> config, Supplier<MetadataStorageTablesConfig> dbTables) public PostgreSQLConnector(Supplier<MetadataStorageConnectorConfig> config, Supplier<MetadataStorageTablesConfig> dbTables)
{ {
@ -68,6 +71,18 @@ public class PostgreSQLConnector extends SQLMetadataConnector
return SERIAL_TYPE; return SERIAL_TYPE;
} }
protected boolean canUpsert(Handle handle) throws SQLException
{
if (canUpsert == null) {
DatabaseMetaData metaData = handle.getConnection().getMetaData();
canUpsert = metaData.getDatabaseMajorVersion() > 9 || (
metaData.getDatabaseMajorVersion() == 9 &&
metaData.getDatabaseMinorVersion() >= 5
);
}
return canUpsert;
}
@Override @Override
public boolean tableExists(final Handle handle, final String tableName) public boolean tableExists(final Handle handle, final String tableName)
{ {
@ -95,21 +110,35 @@ public class PostgreSQLConnector extends SQLMetadataConnector
@Override @Override
public Void withHandle(Handle handle) throws Exception public Void withHandle(Handle handle) throws Exception
{ {
handle.createStatement( if (canUpsert(handle)) {
String.format( handle.createStatement(
"BEGIN;\n" + String.format(
"LOCK TABLE %1$s IN SHARE ROW EXCLUSIVE MODE;\n" + "INSERT INTO %1$s (%2$s, %3$s) VALUES (:key, :value) ON CONFLICT (%2$s) DO UPDATE SET %3$s = EXCLUDED.%3$s",
"WITH upsert AS (UPDATE %1$s SET %3$s=:value WHERE %2$s=:key RETURNING *)\n" + tableName,
" INSERT INTO %1$s (%2$s, %3$s) SELECT :key, :value WHERE NOT EXISTS (SELECT * FROM upsert)\n;" + keyColumn,
"COMMIT;", valueColumn
tableName, )
keyColumn, )
valueColumn .bind("key", key)
) .bind("value", value)
) .execute();
.bind("key", key) } else {
.bind("value", value) handle.createStatement(
.execute(); String.format(
"BEGIN;\n" +
"LOCK TABLE %1$s IN SHARE ROW EXCLUSIVE MODE;\n" +
"WITH upsert AS (UPDATE %1$s SET %3$s=:value WHERE %2$s=:key RETURNING *)\n" +
" INSERT INTO %1$s (%2$s, %3$s) SELECT :key, :value WHERE NOT EXISTS (SELECT * FROM upsert)\n;" +
"COMMIT;",
tableName,
keyColumn,
valueColumn
)
)
.bind("key", key)
.bind("value", value)
.execute();
}
return null; return null;
} }
} }