From dbdbb1d8d4d3ddb0474754a2da584a873a2dc894 Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Wed, 19 Oct 2011 12:43:44 +0100
Subject: [PATCH] Never reuse contact IDs.

---
 components/net/sf/briar/db/H2Database.java   |  3 +-
 components/net/sf/briar/db/JdbcDatabase.java | 32 +++++++++++---------
 test/net/sf/briar/db/H2DatabaseTest.java     |  6 ++--
 3 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/components/net/sf/briar/db/H2Database.java b/components/net/sf/briar/db/H2Database.java
index b61172b65b..18aff631c6 100644
--- a/components/net/sf/briar/db/H2Database.java
+++ b/components/net/sf/briar/db/H2Database.java
@@ -38,7 +38,8 @@ class H2Database extends JdbcDatabase {
 			@DatabaseMaxSize long maxSize,
 			ConnectionWindowFactory connectionWindowFactory,
 			GroupFactory groupFactory) {
-		super(connectionWindowFactory, groupFactory, "BINARY(32)", "BINARY");
+		super(connectionWindowFactory, groupFactory, "BINARY(32)", "BINARY",
+				"INT NOT NULL AUTO_INCREMENT");
 		home = new File(dir, "db");
 		this.password = password;
 		url = "jdbc:h2:split:" + home.getPath()
diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java
index 6bd7cb3e8e..df59f88b23 100644
--- a/components/net/sf/briar/db/JdbcDatabase.java
+++ b/components/net/sf/briar/db/JdbcDatabase.java
@@ -55,7 +55,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 
 	private static final String CREATE_CONTACTS =
 		"CREATE TABLE contacts"
-		+ " (contactId INT NOT NULL,"
+		+ " (contactId COUNTER,"
 		+ " secret BINARY NOT NULL,"
 		+ " PRIMARY KEY (contactId))";
 
@@ -228,7 +228,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 		Logger.getLogger(JdbcDatabase.class.getName());
 
 	// Different database libraries use different names for certain types
-	private final String hashType, binaryType;
+	private final String hashType, binaryType, counterType;
 	private final ConnectionWindowFactory connectionWindowFactory;
 	private final GroupFactory groupFactory;
 	private final LinkedList<Connection> connections =
@@ -240,11 +240,13 @@ abstract class JdbcDatabase implements Database<Connection> {
 	protected abstract Connection createConnection() throws SQLException;
 
 	JdbcDatabase(ConnectionWindowFactory connectionWindowFactory,
-			GroupFactory groupFactory, String hashType, String binaryType) {
+			GroupFactory groupFactory, String hashType, String binaryType,
+			String counterType) {
 		this.connectionWindowFactory = connectionWindowFactory;
 		this.groupFactory = groupFactory;
 		this.hashType = hashType;
 		this.binaryType = binaryType;
+		this.counterType = counterType;
 	}
 
 	protected void open(boolean resume, File dir, String driverClass)
@@ -321,6 +323,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 	private String insertTypeNames(String s) {
 		s = s.replaceAll("HASH", hashType);
 		s = s.replaceAll("BINARY", binaryType);
+		s = s.replaceAll("COUNTER", counterType);
 		return s;
 	}
 
@@ -467,25 +470,24 @@ abstract class JdbcDatabase implements Database<Connection> {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			// Get the highest existing contact ID
-			String sql = "SELECT contactId FROM contacts"
+			// Create a new contact row
+			String sql = "INSERT INTO contacts (secret) VALUES (?)";
+			ps = txn.prepareStatement(sql);
+			ps.setBytes(1, secret);
+			int affected = ps.executeUpdate();
+			if(affected != 1) throw new DbStateException();
+			ps.close();
+			// Get the new (highest) contact ID
+			sql = "SELECT contactId FROM contacts"
 				+ " ORDER BY contactId DESC LIMIT ?";
 			ps = txn.prepareStatement(sql);
 			ps.setInt(1, 1);
 			rs = ps.executeQuery();
-			int nextId = rs.next() ? rs.getInt(1) + 1 : 1;
-			ContactId c = new ContactId(nextId);
+			if(!rs.next()) throw new DbStateException();
+			ContactId c = new ContactId(rs.getInt(1));
 			if(rs.next()) throw new DbStateException();
 			rs.close();
 			ps.close();
-			// Create a new contact row
-			sql = "INSERT INTO contacts (contactId, secret) VALUES (?, ?)";
-			ps = txn.prepareStatement(sql);
-			ps.setInt(1, c.getInt());
-			ps.setBytes(2, secret);
-			int affected = ps.executeUpdate();
-			if(affected != 1) throw new DbStateException();
-			ps.close();
 			// Store the contact's transport properties
 			sql = "INSERT INTO contactTransports"
 				+ " (contactId, transportId, key, value)"
diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java
index 6f609e62ee..fbbbbd3c60 100644
--- a/test/net/sf/briar/db/H2DatabaseTest.java
+++ b/test/net/sf/briar/db/H2DatabaseTest.java
@@ -186,9 +186,9 @@ public class H2DatabaseTest extends TestCase {
 		assertFalse(db.containsContact(txn, contactId2));
 		assertEquals(contactId2, db.addContact(txn, transports, secret));
 		assertTrue(db.containsContact(txn, contactId2));
-		// Delete one of the contacts
-		db.removeContact(txn, contactId1);
-		assertFalse(db.containsContact(txn, contactId1));
+		// Delete the contact with the highest ID
+		db.removeContact(txn, contactId2);
+		assertFalse(db.containsContact(txn, contactId2));
 		// Add another contact - a new ID should be created
 		assertFalse(db.containsContact(txn, contactId3));
 		assertEquals(contactId3, db.addContact(txn, transports, secret));
-- 
GitLab