Skip to content
Permalink
Browse files
Use generatedKeys to fetch sequence values on insertRow() (#1743)
* Use generatedKeys to fetch sequence values on insertRow().
  • Loading branch information
kimjand committed May 6, 2020
1 parent 302046f commit 9f398c537447d7773971ff0e1a93ed75f5b01122
Showing 2 changed files with 167 additions and 65 deletions.
@@ -1001,7 +1001,7 @@ public synchronized void insertRow() throws SQLException {
}

insertSQL.append(paramSQL.toString());
insertStatement = connection.prepareStatement(insertSQL.toString());
insertStatement = connection.prepareStatement(insertSQL.toString(), Statement.RETURN_GENERATED_KEYS);

Iterator<Object> values = updateValues.values().iterator();

@@ -1021,7 +1021,7 @@ public synchronized void insertRow() throws SQLException {
}

// update the underlying row to the new inserted data
updateRowBuffer();
updateRowBuffer(true);

rows.add(rowBuffer);

@@ -1375,7 +1375,7 @@ public synchronized void updateRow() throws SQLException {
updateStatement.close();
updateStatement = null;

updateRowBuffer();
updateRowBuffer(false);

connection.getLogger().log(Level.FINE, "copying data");
thisRow = rowBuffer.readOnlyCopy();
@@ -1659,73 +1659,95 @@ private void parseQuery() {
}
}

private void updateRowBuffer() throws SQLException {
private void setRowBufferColumn(int columnIndex, Object valueObject) throws SQLException {
if (valueObject instanceof PGobject) {
String value = ((PGobject) valueObject).getValue();
rowBuffer.set(columnIndex, (value == null) ? null : connection.encodeString(value));
} else {
switch (getSQLType(columnIndex + 1)) {

// boolean needs to be formatted as t or f instead of true or false
case Types.BIT:
case Types.BOOLEAN:
rowBuffer.set(columnIndex, connection
.encodeString(((Boolean) valueObject).booleanValue() ? "t" : "f"));
break;
//
// toString() isn't enough for date and time types; we must format it correctly
// or we won't be able to re-parse it.
//
case Types.DATE:
rowBuffer.set(columnIndex, connection
.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Date) valueObject)));
break;

case Types.TIME:
rowBuffer.set(columnIndex, connection
.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Time) valueObject)));
break;

case Types.TIMESTAMP:
rowBuffer.set(columnIndex, connection.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Timestamp) valueObject)));
break;

case Types.NULL:
// Should never happen?
break;

case Types.BINARY:
case Types.LONGVARBINARY:
case Types.VARBINARY:
if (isBinary(columnIndex + 1)) {
rowBuffer.set(columnIndex, (byte[]) valueObject);
} else {
try {
rowBuffer.set(columnIndex,
PGbytea.toPGString((byte[]) valueObject).getBytes("ISO-8859-1"));
} catch (UnsupportedEncodingException e) {
throw new PSQLException(
GT.tr("The JVM claims not to support the encoding: {0}", "ISO-8859-1"),
PSQLState.UNEXPECTED_ERROR, e);
}
}
break;

default:
rowBuffer.set(columnIndex, connection.encodeString(String.valueOf(valueObject)));
break;
}

}
}

private void updateRowBuffer(boolean isInsert) throws SQLException {

for (Map.Entry<String, Object> entry : updateValues.entrySet()) {
int columnIndex = findColumn(entry.getKey()) - 1;

Object valueObject = entry.getValue();
if (valueObject instanceof PGobject) {
String value = ((PGobject) valueObject).getValue();
rowBuffer.set(columnIndex, (value == null) ? null : connection.encodeString(value));
} else {
switch (getSQLType(columnIndex + 1)) {

// boolean needs to be formatted as t or f instead of true or false
case Types.BIT:
case Types.BOOLEAN:
rowBuffer.set(columnIndex, connection
.encodeString(((Boolean) valueObject).booleanValue() ? "t" : "f"));
break;
//
// toString() isn't enough for date and time types; we must format it correctly
// or we won't be able to re-parse it.
//
case Types.DATE:
rowBuffer.set(columnIndex, connection
.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Date) valueObject)));
break;

case Types.TIME:
rowBuffer.set(columnIndex, connection
.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Time) valueObject)));
break;

case Types.TIMESTAMP:
rowBuffer.set(columnIndex, connection.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Timestamp) valueObject)));
break;

case Types.NULL:
// Should never happen?
break;

case Types.BINARY:
case Types.LONGVARBINARY:
case Types.VARBINARY:
if (isBinary(columnIndex + 1)) {
rowBuffer.set(columnIndex, (byte[]) valueObject);
} else {
try {
rowBuffer.set(columnIndex,
PGbytea.toPGString((byte[]) valueObject).getBytes("ISO-8859-1"));
} catch (UnsupportedEncodingException e) {
throw new PSQLException(
GT.tr("The JVM claims not to support the encoding: {0}", "ISO-8859-1"),
PSQLState.UNEXPECTED_ERROR, e);
}
}
break;
setRowBufferColumn(columnIndex, valueObject);
}

default:
rowBuffer.set(columnIndex, connection.encodeString(String.valueOf(valueObject)));
break;
}
if (isInsert) {
final ResultSet generatedKeys = insertStatement.getGeneratedKeys();
try {
generatedKeys.next();

int numKeys = primaryKeys.size();

for (int i = 0; i < numKeys; i++) {
final PrimaryKey key = primaryKeys.get(i);
int columnIndex = key.index - 1;
Object valueObject = generatedKeys.getObject(key.name);
setRowBufferColumn(columnIndex, valueObject);
}
} finally {
generatedKeys.close();
}
}
}
@@ -40,6 +40,10 @@ public void setUp() throws Exception {
TestUtil.createTable(con, "updateable",
"id int primary key, name text, notselected text, ts timestamp with time zone, intarr int[]");
TestUtil.createTable(con, "second", "id1 int primary key, name1 text");
TestUtil.createTable(con, "serialtable", "gen_id serial primary key, name text");
TestUtil.createTable(con, "compositepktable", "gen_id serial, name text, dec_id serial");
TestUtil.execute( "alter sequence compositepktable_dec_id_seq increment by 10; alter sequence compositepktable_dec_id_seq restart with 10", con);
TestUtil.execute( "alter table compositepktable add primary key ( gen_id, dec_id )", con);
TestUtil.createTable(con, "stream", "id int primary key, asi text, chr text, bin bytea");
TestUtil.createTable(con, "multicol", "id1 int not null, id2 int not null, val text");
TestUtil.createTable(con, "booltable", "id int not null primary key, b boolean default false");
@@ -58,6 +62,8 @@ public void setUp() throws Exception {
public void tearDown() throws SQLException {
TestUtil.dropTable(con, "updateable");
TestUtil.dropTable(con, "second");
TestUtil.dropTable(con, "serialtable");
TestUtil.dropTable(con, "compositepktable");
TestUtil.dropTable(con, "stream");
TestUtil.dropTable(con, "booltable");
super.tearDown();
@@ -184,6 +190,80 @@ public void testPositioning() throws SQLException {
stmt.close();
}

@Test
public void testReturnSerial() throws Exception {
final String ole = "Ole";

Statement st = null;
ResultSet rs = null;
try {
st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = st.executeQuery("SELECT * FROM serialtable");

rs.moveToInsertRow();
rs.updateString("name", ole);
rs.insertRow();

assertTrue(rs.first());
assertEquals(1, rs.getInt("gen_id"));
assertEquals(ole, rs.getString("name"));

} finally {
TestUtil.closeQuietly(rs);
TestUtil.closeQuietly(st);
}

final String ole2 = "OleOle";
try {
st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = st.executeQuery("SELECT name, gen_id FROM serialtable");

rs.moveToInsertRow();
rs.updateString("name", ole2);
rs.insertRow();

assertTrue(rs.first());
assertEquals(1, rs.getInt("gen_id"));
assertEquals(ole, rs.getString("name"));

assertTrue(rs.last());
assertEquals(2, rs.getInt("gen_id"));
assertEquals(ole2, rs.getString("name"));

} finally {
TestUtil.closeQuietly(rs);
TestUtil.closeQuietly(st);
}

final String dec = "Dec";
try {
st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = st.executeQuery("SELECT * FROM compositepktable");

rs.moveToInsertRow();
rs.updateString("name", dec);
rs.insertRow();

assertTrue(rs.first());
assertEquals(1, rs.getInt("gen_id"));
assertEquals(dec, rs.getString("name"));
assertEquals(10, rs.getInt("dec_id"));

rs.moveToInsertRow();
rs.updateString("name", dec);
rs.insertRow();

assertTrue(rs.last());
assertEquals(2, rs.getInt("gen_id"));
assertEquals(dec, rs.getString("name"));
assertEquals(20, rs.getInt("dec_id"));

} finally {
TestUtil.closeQuietly(rs);
TestUtil.closeQuietly(st);
}
}

@Test
public void testUpdateTimestamp() throws SQLException {
TimeZone origTZ = TimeZone.getDefault();

0 comments on commit 9f398c5

Please sign in to comment.