diff --git a/migrations/0002_schema.up.sql b/migrations/0002_schema.up.sql new file mode 100644 index 0000000..cf279f8 --- /dev/null +++ b/migrations/0002_schema.up.sql @@ -0,0 +1,46 @@ +-- 0002_schema_up.sql + +-- ******************************************** -- +-- Change primary key of block table to height. -- +-- ******************************************** -- + +-- Create new table +CREATE TABLE IF NOT EXISTS block_new( + height INTEGER PRIMARY KEY NOT NULL, + hash TEXT NOT NULL +); +-- Copy only unique rows +INSERT INTO block_new(height, hash) +SELECT height, hash +FROM block +WHERE height IN( + SELECT height + FROM block + GROUP BY height + HAVING COUNT(*) = 1 +); +-- Drop old table +DROP TABLE block; +-- Rename new table to old +ALTER TABLE block_new RENAME TO block; + +-- ************************************************ -- +-- Change type of anchor block_hash column to TEXT. -- +-- ************************************************ -- + +-- Create new table +CREATE TABLE IF NOT EXISTS anchor_new( + block_height INTEGER NOT NULL, + block_hash TEXT NOT NULL, + txid TEXT NOT NULL, + confirmation_time INTEGER NOT NULL, + PRIMARY KEY(block_height, block_hash, txid) +); +-- Copy old data +INSERT INTO anchor_new(block_height, block_hash, txid, confirmation_time) +SELECT block_height, block_hash, txid, confirmation_time +FROM anchor; +-- Delete old table +DROP TABLE anchor; +-- Rename new table to old table +ALTER TABLE anchor_new RENAME TO anchor; diff --git a/src/async_store.rs b/src/async_store.rs index 12a661e..dd1e5fa 100644 --- a/src/async_store.rs +++ b/src/async_store.rs @@ -140,20 +140,11 @@ impl Store { for (&height, hash) in &local_chain.blocks { match hash { Some(hash) => { - // Avoid inserting new rows of existing height. - // FIXME: The correct way to handle this is to have a unique constraint on `height` - // in the block table schema. - let row_option = sqlx::query("SELECT height FROM block WHERE height = $1") + sqlx::query("INSERT OR IGNORE INTO block(height, hash) VALUES($1, $2)") .bind(height) - .fetch_optional(&self.pool) + .bind(hash.to_string()) + .execute(&self.pool) .await?; - if row_option.is_none() { - sqlx::query("INSERT OR IGNORE INTO block(height, hash) VALUES($1, $2)") - .bind(height) - .bind(hash.to_string()) - .execute(&self.pool) - .await?; - } } None => { sqlx::query("DELETE FROM block WHERE height = $1")