From bef0af6ed89a97cfa7c771d86a6bca1edee4cb38 Mon Sep 17 00:00:00 2001
From: a <a@a.a>
Date: Thu, 1 Sep 2022 03:47:47 -0500
Subject: [PATCH] move ref into inline comments

---
 lib/gat/client.go                             |  750 +++++++++++
 lib/gat/server.go                             |   32 +-
 rust_ref/.dockerignore                        |    4 -
 rust_ref/CONTRIBUTING.md                      |   13 -
 rust_ref/Cargo.lock                           | 1170 -----------------
 rust_ref/Cargo.toml                           |   36 -
 rust_ref/Dockerfile                           |   11 -
 rust_ref/Dockerfile.ci                        |    8 -
 rust_ref/LICENSE                              |   20 -
 rust_ref/README.md                            |  512 --------
 rust_ref/docker-compose.yml                   |   17 -
 rust_ref/examples/docker/pgcat.toml           |  147 ---
 rust_ref/pgcat.toml                           |  147 ---
 rust_ref/src/admin.rs                         |  441 -------
 rust_ref/src/client.rs                        | 1081 ---------------
 rust_ref/src/config.rs                        |  672 ----------
 rust_ref/src/constants.rs                     |   33 -
 rust_ref/src/errors.rs                        |   16 -
 rust_ref/src/main.rs                          |  337 -----
 rust_ref/src/messages.rs                      |  514 --------
 rust_ref/src/pool.rs                          |  626 ---------
 rust_ref/src/prometheus.rs                    |  210 ---
 rust_ref/src/query_router.rs                  |  657 ---------
 rust_ref/src/scram.rs                         |  320 -----
 rust_ref/src/server.rs                        |  614 ---------
 rust_ref/src/sharding.rs                      |  204 ---
 rust_ref/src/stats.rs                         |  564 --------
 rust_ref/src/tls.rs                           |   57 -
 rust_ref/tests/docker/Dockerfile              |    5 -
 rust_ref/tests/docker/docker-compose.yml      |   47 -
 rust_ref/tests/docker/run.sh                  |   21 -
 rust_ref/tests/pgbench/simple.sql             |   39 -
 rust_ref/tests/python/.gitignore              |    1 -
 rust_ref/tests/python/requirements.txt        |    2 -
 rust_ref/tests/python/tests.py                |  252 ----
 rust_ref/tests/ruby/.ruby-version             |    2 -
 rust_ref/tests/ruby/Gemfile                   |    8 -
 rust_ref/tests/ruby/Gemfile.lock              |   74 --
 rust_ref/tests/ruby/helpers/pg_instance.rb    |   82 --
 rust_ref/tests/ruby/helpers/pgcat_helper.rb   |  100 --
 rust_ref/tests/ruby/helpers/pgcat_process.rb  |  116 --
 rust_ref/tests/ruby/load_balancing_spec.rb    |   61 -
 rust_ref/tests/ruby/misc_spec.rb              |  109 --
 rust_ref/tests/ruby/routing_spec.rb           |   81 --
 rust_ref/tests/ruby/spec_helper.rb            |   21 -
 rust_ref/tests/ruby/tests.rb                  |  113 --
 rust_ref/tests/sharding/README.md             |   35 -
 .../sharding/partition_hash_test_setup.sql    |   26 -
 rust_ref/tests/sharding/query_routing.sh      |   19 -
 .../tests/sharding/query_routing_setup.sql    |  104 --
 .../sharding/query_routing_test_insert.sql    |   55 -
 .../query_routing_test_primary_replica.sql    |  162 ---
 .../sharding/query_routing_test_select.sql    |   49 -
 .../sharding/query_routing_test_validate.sql  |   11 -
 54 files changed, 781 insertions(+), 10027 deletions(-)
 delete mode 100644 rust_ref/.dockerignore
 delete mode 100644 rust_ref/CONTRIBUTING.md
 delete mode 100644 rust_ref/Cargo.lock
 delete mode 100644 rust_ref/Cargo.toml
 delete mode 100644 rust_ref/Dockerfile
 delete mode 100644 rust_ref/Dockerfile.ci
 delete mode 100644 rust_ref/LICENSE
 delete mode 100644 rust_ref/README.md
 delete mode 100644 rust_ref/docker-compose.yml
 delete mode 100644 rust_ref/examples/docker/pgcat.toml
 delete mode 100644 rust_ref/pgcat.toml
 delete mode 100644 rust_ref/src/admin.rs
 delete mode 100644 rust_ref/src/client.rs
 delete mode 100644 rust_ref/src/config.rs
 delete mode 100644 rust_ref/src/constants.rs
 delete mode 100644 rust_ref/src/errors.rs
 delete mode 100644 rust_ref/src/main.rs
 delete mode 100644 rust_ref/src/messages.rs
 delete mode 100644 rust_ref/src/pool.rs
 delete mode 100644 rust_ref/src/prometheus.rs
 delete mode 100644 rust_ref/src/query_router.rs
 delete mode 100644 rust_ref/src/scram.rs
 delete mode 100644 rust_ref/src/server.rs
 delete mode 100644 rust_ref/src/sharding.rs
 delete mode 100644 rust_ref/src/stats.rs
 delete mode 100644 rust_ref/src/tls.rs
 delete mode 100644 rust_ref/tests/docker/Dockerfile
 delete mode 100644 rust_ref/tests/docker/docker-compose.yml
 delete mode 100644 rust_ref/tests/docker/run.sh
 delete mode 100644 rust_ref/tests/pgbench/simple.sql
 delete mode 100644 rust_ref/tests/python/.gitignore
 delete mode 100644 rust_ref/tests/python/requirements.txt
 delete mode 100644 rust_ref/tests/python/tests.py
 delete mode 100644 rust_ref/tests/ruby/.ruby-version
 delete mode 100644 rust_ref/tests/ruby/Gemfile
 delete mode 100644 rust_ref/tests/ruby/Gemfile.lock
 delete mode 100644 rust_ref/tests/ruby/helpers/pg_instance.rb
 delete mode 100644 rust_ref/tests/ruby/helpers/pgcat_helper.rb
 delete mode 100644 rust_ref/tests/ruby/helpers/pgcat_process.rb
 delete mode 100644 rust_ref/tests/ruby/load_balancing_spec.rb
 delete mode 100644 rust_ref/tests/ruby/misc_spec.rb
 delete mode 100644 rust_ref/tests/ruby/routing_spec.rb
 delete mode 100644 rust_ref/tests/ruby/spec_helper.rb
 delete mode 100644 rust_ref/tests/ruby/tests.rb
 delete mode 100644 rust_ref/tests/sharding/README.md
 delete mode 100644 rust_ref/tests/sharding/partition_hash_test_setup.sql
 delete mode 100644 rust_ref/tests/sharding/query_routing.sh
 delete mode 100644 rust_ref/tests/sharding/query_routing_setup.sql
 delete mode 100644 rust_ref/tests/sharding/query_routing_test_insert.sql
 delete mode 100644 rust_ref/tests/sharding/query_routing_test_primary_replica.sql
 delete mode 100644 rust_ref/tests/sharding/query_routing_test_select.sql
 delete mode 100644 rust_ref/tests/sharding/query_routing_test_validate.sql

diff --git a/lib/gat/client.go b/lib/gat/client.go
index 123143ff..96ab5dbf 100644
--- a/lib/gat/client.go
+++ b/lib/gat/client.go
@@ -85,3 +85,753 @@ func NewClient(
 func (c *Client) Accept(ctx context.Context) error {
 	return nil
 }
+
+//impl<S, T> Client<S, T>
+//where
+//    S: tokio::io::AsyncRead + std::marker::Unpin,
+//    T: tokio::io::AsyncWrite + std::marker::Unpin,
+//{
+//    pub fn is_admin(&self) -> bool {
+//        self.admin
+//    }
+//
+//    /// Handle Postgres client startup after TLS negotiation is complete
+//    /// or over plain text.
+//    pub async fn startup(
+//        mut read: S,
+//        mut write: T,
+//        addr: std::net::SocketAddr,
+//        bytes: BytesMut, // The rest of the startup message.
+//        client_server_map: ClientServerMap,
+//        shutdown: Receiver<()>,
+//        admin_only: bool,
+//    ) -> Result<Client<S, T>, Error> {
+//        let config = get_config();
+//        let stats = get_reporter();
+//        let parameters = parse_startup(bytes.clone())?;
+//
+//        // These two parameters are mandatory by the protocol.
+//        let pool_name = match parameters.get("database") {
+//            Some(db) => db,
+//            None => return Err(Error::ClientError),
+//        };
+//
+//        let username = match parameters.get("user") {
+//            Some(user) => user,
+//            None => return Err(Error::ClientError),
+//        };
+//
+//        let admin = ["pgcat", "pgbouncer"]
+//            .iter()
+//            .filter(|db| *db == &pool_name)
+//            .count()
+//            == 1;
+//
+//        // Kick any client that's not admin while we're in admin-only mode.
+//        if !admin && admin_only {
+//            debug!(
+//                "Rejecting non-admin connection to {} when in admin only mode",
+//                pool_name
+//            );
+//            error_response_terminal(
+//                &mut write,
+//                &format!("terminating connection due to administrator command"),
+//            )
+//            .await?;
+//            return Err(Error::ShuttingDown);
+//        }
+//
+//        // Generate random backend ID and secret key
+//        let process_id: i32 = rand::random();
+//        let secret_key: i32 = rand::random();
+//
+//        // Perform MD5 authentication.
+//        // TODO: Add SASL support.
+//        let salt = md5_challenge(&mut write).await?;
+//
+//        let code = match read.read_u8().await {
+//            Ok(p) => p,
+//            Err(_) => return Err(Error::SocketError),
+//        };
+//
+//        // PasswordMessage
+//        if code as char != 'p' {
+//            debug!("Expected p, got {}", code as char);
+//            return Err(Error::ProtocolSyncError);
+//        }
+//
+//        let len = match read.read_i32().await {
+//            Ok(len) => len,
+//            Err(_) => return Err(Error::SocketError),
+//        };
+//
+//        let mut password_response = vec![0u8; (len - 4) as usize];
+//
+//        match read.read_exact(&mut password_response).await {
+//            Ok(_) => (),
+//            Err(_) => return Err(Error::SocketError),
+//        };
+//
+//        // Authenticate admin user.
+//        let (transaction_mode, server_info) = if admin {
+//            // Compare server and client hashes.
+//            let password_hash = md5_hash_password(
+//                &config.general.admin_username,
+//                &config.general.admin_password,
+//                &salt,
+//            );
+//
+//            if password_hash != password_response {
+//                debug!("Password authentication failed");
+//                wrong_password(&mut write, username).await?;
+//
+//                return Err(Error::ClientError);
+//            }
+//
+//            (false, generate_server_info_for_admin())
+//        }
+//        // Authenticate normal user.
+//        else {
+//            let pool = match get_pool(pool_name.clone(), username.clone()) {
+//                Some(pool) => pool,
+//                None => {
+//                    error_response(
+//                        &mut write,
+//                        &format!(
+//                            "No pool configured for database: {:?}, user: {:?}",
+//                            pool_name, username
+//                        ),
+//                    )
+//                    .await?;
+//
+//                    return Err(Error::ClientError);
+//                }
+//            };
+//
+//            // Compare server and client hashes.
+//            let password_hash = md5_hash_password(&username, &pool.settings.user.password, &salt);
+//
+//            if password_hash != password_response {
+//                debug!("Password authentication failed");
+//                wrong_password(&mut write, username).await?;
+//
+//                return Err(Error::ClientError);
+//            }
+//
+//            let transaction_mode = pool.settings.pool_mode == PoolMode::Transaction;
+//
+//            (transaction_mode, pool.server_info())
+//        };
+//
+//        debug!("Password authentication successful");
+//
+//        auth_ok(&mut write).await?;
+//        write_all(&mut write, server_info).await?;
+//        backend_key_data(&mut write, process_id, secret_key).await?;
+//        ready_for_query(&mut write).await?;
+//
+//        trace!("Startup OK");
+//
+//        return Ok(Client {
+//            read: BufReader::new(read),
+//            write: write,
+//            addr,
+//            buffer: BytesMut::with_capacity(8196),
+//            cancel_mode: false,
+//            transaction_mode,
+//            process_id,
+//            secret_key,
+//            client_server_map,
+//            parameters: parameters.clone(),
+//            stats: stats,
+//            admin: admin,
+//            last_address_id: None,
+//            last_server_id: None,
+//            pool_name: pool_name.clone(),
+//            username: username.clone(),
+//            shutdown,
+//            connected_to_server: false,
+//        });
+//    }
+//
+//    /// Handle cancel request.
+//    pub async fn cancel(
+//        read: S,
+//        write: T,
+//        addr: std::net::SocketAddr,
+//        mut bytes: BytesMut, // The rest of the startup message.
+//        client_server_map: ClientServerMap,
+//        shutdown: Receiver<()>,
+//    ) -> Result<Client<S, T>, Error> {
+//        let process_id = bytes.get_i32();
+//        let secret_key = bytes.get_i32();
+//        return Ok(Client {
+//            read: BufReader::new(read),
+//            write: write,
+//            addr,
+//            buffer: BytesMut::with_capacity(8196),
+//            cancel_mode: true,
+//            transaction_mode: false,
+//            process_id,
+//            secret_key,
+//            client_server_map,
+//            parameters: HashMap::new(),
+//            stats: get_reporter(),
+//            admin: false,
+//            last_address_id: None,
+//            last_server_id: None,
+//            pool_name: String::from("undefined"),
+//            username: String::from("undefined"),
+//            shutdown,
+//            connected_to_server: false,
+//        });
+//    }
+//
+//    /// Handle a connected and authenticated client.
+//    pub async fn handle(&mut self) -> Result<(), Error> {
+//        // The client wants to cancel a query it has issued previously.
+//        if self.cancel_mode {
+//            trace!("Sending CancelRequest");
+//
+//            let (process_id, secret_key, address, port) = {
+//                let guard = self.client_server_map.lock();
+//
+//                match guard.get(&(self.process_id, self.secret_key)) {
+//                    // Drop the mutex as soon as possible.
+//                    // We found the server the client is using for its query
+//                    // that it wants to cancel.
+//                    Some((process_id, secret_key, address, port)) => (
+//                        process_id.clone(),
+//                        secret_key.clone(),
+//                        address.clone(),
+//                        *port,
+//                    ),
+//
+//                    // The client doesn't know / got the wrong server,
+//                    // we're closing the connection for security reasons.
+//                    None => return Ok(()),
+//                }
+//            };
+//
+//            // Opens a new separate connection to the server, sends the backend_id
+//            // and secret_key and then closes it for security reasons. No other interactions
+//            // take place.
+//            return Ok(Server::cancel(&address, port, process_id, secret_key).await?);
+//        }
+//
+//        // The query router determines where the query is going to go,
+//        // e.g. primary, replica, which shard.
+//        let mut query_router = QueryRouter::new();
+//
+//        // Our custom protocol loop.
+//        // We expect the client to either start a transaction with regular queries
+//        // or issue commands for our sharding and server selection protocol.
+//        loop {
+//            trace!(
+//                "Client idle, waiting for message, transaction mode: {}",
+//                self.transaction_mode
+//            );
+//
+//            // Read a complete message from the client, which normally would be
+//            // either a `Q` (query) or `P` (prepare, extended protocol).
+//            // We can parse it here before grabbing a server from the pool,
+//            // in case the client is sending some custom protocol messages, e.g.
+//            // SET SHARDING KEY TO 'bigint';
+//
+//            let mut message = tokio::select! {
+//                _ = self.shutdown.recv() => {
+//                    if !self.admin {
+//                        error_response_terminal(
+//                            &mut self.write,
+//                            &format!("terminating connection due to administrator command")
+//                        ).await?;
+//                        return Ok(())
+//                    }
+//
+//                    // Admin clients ignore shutdown.
+//                    else {
+//                        read_message(&mut self.read).await?
+//                    }
+//                },
+//                message_result = read_message(&mut self.read) => message_result?
+//            };
+//
+//            // Avoid taking a server if the client just wants to disconnect.
+//            if message[0] as char == 'X' {
+//                debug!("Client disconnecting");
+//                return Ok(());
+//            }
+//
+//            // Handle admin database queries.
+//            if self.admin {
+//                debug!("Handling admin command");
+//                handle_admin(&mut self.write, message, self.client_server_map.clone()).await?;
+//                continue;
+//            }
+//
+//            // Get a pool instance referenced by the most up-to-date
+//            // pointer. This ensures we always read the latest config
+//            // when starting a query.
+//            let pool = match get_pool(self.pool_name.clone(), self.username.clone()) {
+//                Some(pool) => pool,
+//                None => {
+//                    error_response(
+//                        &mut self.write,
+//                        &format!(
+//                            "No pool configured for database: {:?}, user: {:?}",
+//                            self.pool_name, self.username
+//                        ),
+//                    )
+//                    .await?;
+//                    return Err(Error::ClientError);
+//                }
+//            };
+//            query_router.update_pool_settings(pool.settings.clone());
+//            let current_shard = query_router.shard();
+//
+//            // Handle all custom protocol commands, if any.
+//            match query_router.try_execute_command(message.clone()) {
+//                // Normal query, not a custom command.
+//                None => {
+//                    if query_router.query_parser_enabled() {
+//                        query_router.infer_role(message.clone());
+//                    }
+//                }
+//
+//                // SET SHARD TO
+//                Some((Command::SetShard, _)) => {
+//                    // Selected shard is not configured.
+//                    if query_router.shard() >= pool.shards() {
+//                        // Set the shard back to what it was.
+//                        query_router.set_shard(current_shard);
+//
+//                        error_response(
+//                            &mut self.write,
+//                            &format!(
+//                                "shard {} is more than configured {}, staying on shard {}",
+//                                query_router.shard(),
+//                                pool.shards(),
+//                                current_shard,
+//                            ),
+//                        )
+//                        .await?;
+//                    } else {
+//                        custom_protocol_response_ok(&mut self.write, "SET SHARD").await?;
+//                    }
+//                    continue;
+//                }
+//
+//                // SET PRIMARY READS TO
+//                Some((Command::SetPrimaryReads, _)) => {
+//                    custom_protocol_response_ok(&mut self.write, "SET PRIMARY READS").await?;
+//                    continue;
+//                }
+//
+//                // SET SHARDING KEY TO
+//                Some((Command::SetShardingKey, _)) => {
+//                    custom_protocol_response_ok(&mut self.write, "SET SHARDING KEY").await?;
+//                    continue;
+//                }
+//
+//                // SET SERVER ROLE TO
+//                Some((Command::SetServerRole, _)) => {
+//                    custom_protocol_response_ok(&mut self.write, "SET SERVER ROLE").await?;
+//                    continue;
+//                }
+//
+//                // SHOW SERVER ROLE
+//                Some((Command::ShowServerRole, value)) => {
+//                    show_response(&mut self.write, "server role", &value).await?;
+//                    continue;
+//                }
+//
+//                // SHOW SHARD
+//                Some((Command::ShowShard, value)) => {
+//                    show_response(&mut self.write, "shard", &value).await?;
+//                    continue;
+//                }
+//
+//                // SHOW PRIMARY READS
+//                Some((Command::ShowPrimaryReads, value)) => {
+//                    show_response(&mut self.write, "primary reads", &value).await?;
+//                    continue;
+//                }
+//            };
+//
+//            debug!("Waiting for connection from pool");
+//
+//            // Grab a server from the pool.
+//            let connection = match pool
+//                .get(query_router.shard(), query_router.role(), self.process_id)
+//                .await
+//            {
+//                Ok(conn) => {
+//                    debug!("Got connection from pool");
+//                    conn
+//                }
+//                Err(err) => {
+//                    // Clients do not expect to get SystemError followed by ReadyForQuery in the middle
+//                    // of extended protocol submission. So we will hold off on sending the actual error
+//                    // message to the client until we get 'S' message
+//                    match message[0] as char {
+//                        'P' | 'B' | 'E' | 'D' => (),
+//                        _ => {
+//                            error_response(
+//                                &mut self.write,
+//                                "could not get connection from the pool",
+//                            )
+//                            .await?;
+//                        }
+//                    };
+//
+//                    error!("Could not get connection from pool: {:?}", err);
+//
+//                    continue;
+//                }
+//            };
+//
+//            let mut reference = connection.0;
+//            let address = connection.1;
+//            let server = &mut *reference;
+//
+//            // Server is assigned to the client in case the client wants to
+//            // cancel a query later.
+//            server.claim(self.process_id, self.secret_key);
+//            self.connected_to_server = true;
+//
+//            // Update statistics.
+//            if let Some(last_address_id) = self.last_address_id {
+//                self.stats
+//                    .client_disconnecting(self.process_id, last_address_id);
+//            }
+//            self.stats.client_active(self.process_id, address.id);
+//
+//            self.last_address_id = Some(address.id);
+//            self.last_server_id = Some(server.process_id());
+//
+//            debug!(
+//                "Client {:?} talking to server {:?}",
+//                self.addr,
+//                server.address()
+//            );
+//
+//            // Set application_name if any.
+//            // TODO: investigate other parameters and set them too.
+//            if self.parameters.contains_key("application_name") {
+//                server
+//                    .set_name(&self.parameters["application_name"])
+//                    .await?;
+//            }
+//
+//            // Transaction loop. Multiple queries can be issued by the client here.
+//            // The connection belongs to the client until the transaction is over,
+//            // or until the client disconnects if we are in session mode.
+//            //
+//            // If the client is in session mode, no more custom protocol
+//            // commands will be accepted.
+//            loop {
+//                let mut message = if message.len() == 0 {
+//                    trace!("Waiting for message inside transaction or in session mode");
+//
+//                    match read_message(&mut self.read).await {
+//                        Ok(message) => message,
+//                        Err(err) => {
+//                            // Client disconnected inside a transaction.
+//                            // Clean up the server and re-use it.
+//                            // This prevents connection thrashing by bad clients.
+//                            if server.in_transaction() {
+//                                server.query("ROLLBACK").await?;
+//                                server.query("DISCARD ALL").await?;
+//                                server.set_name("pgcat").await?;
+//                            }
+//
+//                            return Err(err);
+//                        }
+//                    }
+//                } else {
+//                    let msg = message.clone();
+//                    message.clear();
+//                    msg
+//                };
+//
+//                // The message will be forwarded to the server intact. We still would like to
+//                // parse it below to figure out what to do with it.
+//                let original = message.clone();
+//
+//                let code = message.get_u8() as char;
+//                let _len = message.get_i32() as usize;
+//
+//                trace!("Message: {}", code);
+//
+//                match code {
+//                    // ReadyForQuery
+//                    'Q' => {
+//                        debug!("Sending query to server");
+//
+//                        self.send_and_receive_loop(code, original, server, &address, &pool)
+//                            .await?;
+//
+//                        if !server.in_transaction() {
+//                            // Report transaction executed statistics.
+//                            self.stats.transaction(self.process_id, address.id);
+//
+//                            // Release server back to the pool if we are in transaction mode.
+//                            // If we are in session mode, we keep the server until the client disconnects.
+//                            if self.transaction_mode {
+//                                break;
+//                            }
+//                        }
+//                    }
+//
+//                    // Terminate
+//                    'X' => {
+//                        // Client closing. Rollback and clean up
+//                        // connection before releasing into the pool.
+//                        // Pgbouncer closes the connection which leads to
+//                        // connection thrashing when clients misbehave.
+//                        if server.in_transaction() {
+//                            server.query("ROLLBACK").await?;
+//                            server.query("DISCARD ALL").await?;
+//                            server.set_name("pgcat").await?;
+//                        }
+//
+//                        self.release();
+//
+//                        return Ok(());
+//                    }
+//
+//                    // Parse
+//                    // The query with placeholders is here, e.g. `SELECT * FROM users WHERE email = $1 AND active = $2`.
+//                    'P' => {
+//                        self.buffer.put(&original[..]);
+//                    }
+//
+//                    // Bind
+//                    // The placeholder's replacements are here, e.g. 'user@email.com' and 'true'
+//                    'B' => {
+//                        self.buffer.put(&original[..]);
+//                    }
+//
+//                    // Describe
+//                    // Command a client can issue to describe a previously prepared named statement.
+//                    'D' => {
+//                        self.buffer.put(&original[..]);
+//                    }
+//
+//                    // Execute
+//                    // Execute a prepared statement prepared in `P` and bound in `B`.
+//                    'E' => {
+//                        self.buffer.put(&original[..]);
+//                    }
+//
+//                    // Sync
+//                    // Frontend (client) is asking for the query result now.
+//                    'S' => {
+//                        debug!("Sending query to server");
+//
+//                        self.buffer.put(&original[..]);
+//
+//                        self.send_and_receive_loop(
+//                            code,
+//                            self.buffer.clone(),
+//                            server,
+//                            &address,
+//                            &pool,
+//                        )
+//                        .await?;
+//
+//                        self.buffer.clear();
+//
+//                        if !server.in_transaction() {
+//                            self.stats.transaction(self.process_id, address.id);
+//
+//                            // Release server back to the pool if we are in transaction mode.
+//                            // If we are in session mode, we keep the server until the client disconnects.
+//                            if self.transaction_mode {
+//                                break;
+//                            }
+//                        }
+//                    }
+//
+//                    // CopyData
+//                    'd' => {
+//                        // Forward the data to the server,
+//                        // don't buffer it since it can be rather large.
+//                        self.send_server_message(server, original, &address, &pool)
+//                            .await?;
+//                    }
+//
+//                    // CopyDone or CopyFail
+//                    // Copy is done, successfully or not.
+//                    'c' | 'f' => {
+//                        self.send_server_message(server, original, &address, &pool)
+//                            .await?;
+//
+//                        let response = self.receive_server_message(server, &address, &pool).await?;
+//
+//                        match write_all_half(&mut self.write, response).await {
+//                            Ok(_) => (),
+//                            Err(err) => {
+//                                server.mark_bad();
+//                                return Err(err);
+//                            }
+//                        };
+//
+//                        if !server.in_transaction() {
+//                            self.stats.transaction(self.process_id, address.id);
+//
+//                            // Release server back to the pool if we are in transaction mode.
+//                            // If we are in session mode, we keep the server until the client disconnects.
+//                            if self.transaction_mode {
+//                                break;
+//                            }
+//                        }
+//                    }
+//
+//                    // Some unexpected message. We either did not implement the protocol correctly
+//                    // or this is not a Postgres client we're talking to.
+//                    _ => {
+//                        error!("Unexpected code: {}", code);
+//                    }
+//                }
+//            }
+//
+//            // The server is no longer bound to us, we can't cancel it's queries anymore.
+//            debug!("Releasing server back into the pool");
+//            self.stats.server_idle(server.process_id(), address.id);
+//            self.connected_to_server = false;
+//            self.release();
+//            self.stats.client_idle(self.process_id, address.id);
+//        }
+//    }
+//
+//    /// Release the server from the client: it can't cancel its queries anymore.
+//    pub fn release(&self) {
+//        let mut guard = self.client_server_map.lock();
+//        guard.remove(&(self.process_id, self.secret_key));
+//    }
+//
+//    async fn send_and_receive_loop(
+//        &mut self,
+//        code: char,
+//        message: BytesMut,
+//        server: &mut Server,
+//        address: &Address,
+//        pool: &ConnectionPool,
+//    ) -> Result<(), Error> {
+//        debug!("Sending {} to server", code);
+//
+//        self.send_server_message(server, message, &address, &pool)
+//            .await?;
+//
+//        // Read all data the server has to offer, which can be multiple messages
+//        // buffered in 8196 bytes chunks.
+//        loop {
+//            let response = self.receive_server_message(server, &address, &pool).await?;
+//
+//            match write_all_half(&mut self.write, response).await {
+//                Ok(_) => (),
+//                Err(err) => {
+//                    server.mark_bad();
+//                    return Err(err);
+//                }
+//            };
+//
+//            if !server.is_data_available() {
+//                break;
+//            }
+//        }
+//
+//        // Report query executed statistics.
+//        self.stats.query(self.process_id, address.id);
+//
+//        Ok(())
+//    }
+//
+//    async fn send_server_message(
+//        &self,
+//        server: &mut Server,
+//        message: BytesMut,
+//        address: &Address,
+//        pool: &ConnectionPool,
+//    ) -> Result<(), Error> {
+//        match server.send(message).await {
+//            Ok(_) => Ok(()),
+//            Err(err) => {
+//                pool.ban(address, self.process_id);
+//                Err(err)
+//            }
+//        }
+//    }
+//
+//    async fn receive_server_message(
+//        &mut self,
+//        server: &mut Server,
+//        address: &Address,
+//        pool: &ConnectionPool,
+//    ) -> Result<BytesMut, Error> {
+//        if pool.settings.user.statement_timeout > 0 {
+//            match tokio::time::timeout(
+//                tokio::time::Duration::from_millis(pool.settings.user.statement_timeout),
+//                server.recv(),
+//            )
+//            .await
+//            {
+//                Ok(result) => match result {
+//                    Ok(message) => Ok(message),
+//                    Err(err) => {
+//                        pool.ban(address, self.process_id);
+//                        error_response_terminal(
+//                            &mut self.write,
+//                            &format!("error receiving data from server: {:?}", err),
+//                        )
+//                        .await?;
+//                        Err(err)
+//                    }
+//                },
+//                Err(_) => {
+//                    error!(
+//                        "Statement timeout while talking to {:?} with user {}",
+//                        address, pool.settings.user.username
+//                    );
+//                    server.mark_bad();
+//                    pool.ban(address, self.process_id);
+//                    error_response_terminal(&mut self.write, "pool statement timeout").await?;
+//                    Err(Error::StatementTimeout)
+//                }
+//            }
+//        } else {
+//            match server.recv().await {
+//                Ok(message) => Ok(message),
+//                Err(err) => {
+//                    pool.ban(address, self.process_id);
+//                    error_response_terminal(
+//                        &mut self.write,
+//                        &format!("error receiving data from server: {:?}", err),
+//                    )
+//                    .await?;
+//                    Err(err)
+//                }
+//            }
+//        }
+//    }
+//}
+//
+//impl<S, T> Drop for Client<S, T> {
+//    fn drop(&mut self) {
+//        let mut guard = self.client_server_map.lock();
+//        guard.remove(&(self.process_id, self.secret_key));
+//
+//        // Dirty shutdown
+//        // TODO: refactor, this is not the best way to handle state management.
+//        if let Some(address_id) = self.last_address_id {
+//            self.stats.client_disconnecting(self.process_id, address_id);
+//
+//            if self.connected_to_server {
+//                if let Some(process_id) = self.last_server_id {
+//                    self.stats.server_idle(process_id, address_id);
+//                }
+//            }
+//        }
+//    }
+//}
diff --git a/lib/gat/server.go b/lib/gat/server.go
index 6194373f..85be3a22 100644
--- a/lib/gat/server.go
+++ b/lib/gat/server.go
@@ -303,5 +303,35 @@ func (s *Server) connect(ctx context.Context) error {
 			return nil
 		}
 	}
-
 }
+
+// TODO: implement drop - we should rename to close.
+//impl Drop for Server {
+//    /// Try to do a clean shut down. Best effort because
+//    /// the socket is in non-blocking mode, so it may not be ready
+//    /// for a write.
+//    fn drop(&mut self) {
+//        self.stats
+//            .server_disconnecting(self.process_id(), self.address.id);
+//
+//        let mut bytes = BytesMut::with_capacity(4);
+//        bytes.put_u8(b'X');
+//        bytes.put_i32(4);
+//
+//        match self.write.try_write(&bytes) {
+//            Ok(_) => (),
+//            Err(_) => debug!("Dirty shutdown"),
+//        };
+//
+//        // Should not matter.
+//        self.bad = true;
+//
+//        let now = chrono::offset::Utc::now().naive_utc();
+//        let duration = now - self.connected_at;
+//
+//        info!(
+//            "Server connection closed, session duration: {}",
+//            crate::format_duration(&duration)
+//        );
+//    }
+//}
diff --git a/rust_ref/.dockerignore b/rust_ref/.dockerignore
deleted file mode 100644
index ff42aaaa..00000000
--- a/rust_ref/.dockerignore
+++ /dev/null
@@ -1,4 +0,0 @@
-target/
-tests/
-tracing/
-.circleci/
diff --git a/rust_ref/CONTRIBUTING.md b/rust_ref/CONTRIBUTING.md
deleted file mode 100644
index 10d4924a..00000000
--- a/rust_ref/CONTRIBUTING.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## Introduction
-
-Thank you for contributing! Just a few tips here:
-
-1. `cargo fmt` your code before opening up a PR
-2. Run the test suite (e.g. `pgbench`) to make sure everything still works. The tests are in `.circleci/run_tests.sh`.
-3. Performance is important, make sure there are no regressions in your branch vs. `main`.
-
-Happy hacking!
-
-## TODOs
-
-See [Issues]([url](https://github.com/levkk/pgcat/issues)).
diff --git a/rust_ref/Cargo.lock b/rust_ref/Cargo.lock
deleted file mode 100644
index af4826b8..00000000
--- a/rust_ref/Cargo.lock
+++ /dev/null
@@ -1,1170 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "aho-corasick"
-version = "0.7.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "arc-swap"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f"
-
-[[package]]
-name = "async-trait"
-version = "0.1.52"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
-
-[[package]]
-name = "base64"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
-
-[[package]]
-name = "bb8"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e9f4fa9768efd269499d8fba693260cfc670891cf6de3adc935588447a77cc8"
-dependencies = [
- "async-trait",
- "futures-channel",
- "futures-util",
- "parking_lot",
- "tokio",
-]
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "block-buffer"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "bumpalo"
-version = "3.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
-
-[[package]]
-name = "bytes"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
-
-[[package]]
-name = "cc"
-version = "1.0.73"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "chrono"
-version = "0.4.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
-dependencies = [
- "libc",
- "num-integer",
- "num-traits",
- "time",
- "winapi",
-]
-
-[[package]]
-name = "cpufeatures"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "crypto-common"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
-dependencies = [
- "generic-array",
- "typenum",
-]
-
-[[package]]
-name = "digest"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
-dependencies = [
- "block-buffer",
- "crypto-common",
- "subtle",
-]
-
-[[package]]
-name = "env_logger"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
-dependencies = [
- "atty",
- "humantime",
- "log",
- "regex",
- "termcolor",
-]
-
-[[package]]
-name = "exitcode"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193"
-
-[[package]]
-name = "fnv"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-
-[[package]]
-name = "futures-channel"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
-dependencies = [
- "futures-core",
-]
-
-[[package]]
-name = "futures-core"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
-
-[[package]]
-name = "futures-sink"
-version = "0.3.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
-
-[[package]]
-name = "futures-task"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
-
-[[package]]
-name = "futures-util"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
-dependencies = [
- "futures-channel",
- "futures-core",
- "futures-task",
- "pin-project-lite",
- "pin-utils",
- "slab",
-]
-
-[[package]]
-name = "generic-array"
-version = "0.14.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "h2"
-version = "0.3.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-
-[[package]]
-name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "hmac"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
-dependencies = [
- "digest",
-]
-
-[[package]]
-name = "http"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
-[[package]]
-name = "http-body"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
-dependencies = [
- "bytes",
- "http",
- "pin-project-lite",
-]
-
-[[package]]
-name = "httparse"
-version = "1.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c"
-
-[[package]]
-name = "httpdate"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
-
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
-[[package]]
-name = "hyper"
-version = "0.14.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "httparse",
- "httpdate",
- "itoa",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
- "want",
-]
-
-[[package]]
-name = "indexmap"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
-dependencies = [
- "autocfg",
- "hashbrown",
-]
-
-[[package]]
-name = "instant"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
-
-[[package]]
-name = "js-sys"
-version = "0.3.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "libc"
-version = "0.2.126"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
-
-[[package]]
-name = "lock_api"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
-dependencies = [
- "scopeguard",
-]
-
-[[package]]
-name = "log"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "md-5"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae"
-dependencies = [
- "digest",
-]
-
-[[package]]
-name = "memchr"
-version = "2.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
-
-[[package]]
-name = "mio"
-version = "0.7.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
-dependencies = [
- "libc",
- "log",
- "miow",
- "ntapi",
- "winapi",
-]
-
-[[package]]
-name = "miow"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "ntapi"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
-dependencies = [
- "autocfg",
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "num_cpus"
-version = "1.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
-
-[[package]]
-name = "parking_lot"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
-dependencies = [
- "instant",
- "lock_api",
- "parking_lot_core",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
-dependencies = [
- "cfg-if",
- "instant",
- "libc",
- "redox_syscall",
- "smallvec",
- "winapi",
-]
-
-[[package]]
-name = "pgcat"
-version = "0.6.0-alpha1"
-dependencies = [
- "arc-swap",
- "async-trait",
- "base64",
- "bb8",
- "bytes",
- "chrono",
- "env_logger",
- "exitcode",
- "hmac",
- "hyper",
- "log",
- "md-5",
- "num_cpus",
- "once_cell",
- "parking_lot",
- "phf",
- "rand",
- "regex",
- "rustls-pemfile",
- "serde",
- "serde_derive",
- "sha-1",
- "sha2",
- "sqlparser",
- "stringprep",
- "tokio",
- "tokio-rustls",
- "toml",
-]
-
-[[package]]
-name = "phf"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
-dependencies = [
- "phf_macros",
- "phf_shared",
- "proc-macro-hack",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
-dependencies = [
- "phf_shared",
- "rand",
-]
-
-[[package]]
-name = "phf_macros"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
-dependencies = [
- "phf_generator",
- "phf_shared",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
-dependencies = [
- "siphasher",
-]
-
-[[package]]
-name = "pin-project-lite"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
-
-[[package]]
-name = "pin-utils"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
-
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
- "rand_hc",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.2.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "regex"
-version = "1.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
-
-[[package]]
-name = "ring"
-version = "0.16.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
-dependencies = [
- "cc",
- "libc",
- "once_cell",
- "spin",
- "untrusted",
- "web-sys",
- "winapi",
-]
-
-[[package]]
-name = "rustls"
-version = "0.20.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
-dependencies = [
- "log",
- "ring",
- "sct",
- "webpki",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9"
-dependencies = [
- "base64",
-]
-
-[[package]]
-name = "scopeguard"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
-
-[[package]]
-name = "sct"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
-dependencies = [
- "ring",
- "untrusted",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.136"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
-
-[[package]]
-name = "serde_derive"
-version = "1.0.136"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "sha-1"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest",
-]
-
-[[package]]
-name = "sha2"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest",
-]
-
-[[package]]
-name = "signal-hook-registry"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "siphasher"
-version = "0.3.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
-
-[[package]]
-name = "slab"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
-
-[[package]]
-name = "smallvec"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
-
-[[package]]
-name = "socket2"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "spin"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
-
-[[package]]
-name = "sqlparser"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8f192f29f4aa49e57bebd0aa05858e0a1f32dd270af36efe49edb82cbfffab6"
-dependencies = [
- "log",
-]
-
-[[package]]
-name = "stringprep"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
-name = "subtle"
-version = "2.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
-
-[[package]]
-name = "syn"
-version = "1.0.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
-[[package]]
-name = "termcolor"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "time"
-version = "0.1.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
-dependencies = [
- "libc",
- "wasi",
- "winapi",
-]
-
-[[package]]
-name = "tinyvec"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
-dependencies = [
- "tinyvec_macros",
-]
-
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
-
-[[package]]
-name = "tokio"
-version = "1.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a"
-dependencies = [
- "bytes",
- "libc",
- "memchr",
- "mio",
- "num_cpus",
- "once_cell",
- "parking_lot",
- "pin-project-lite",
- "signal-hook-registry",
- "tokio-macros",
- "winapi",
-]
-
-[[package]]
-name = "tokio-macros"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "tokio-rustls"
-version = "0.23.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
-dependencies = [
- "rustls",
- "tokio",
- "webpki",
-]
-
-[[package]]
-name = "tokio-util"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c"
-dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
- "pin-project-lite",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "toml"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "tower-service"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
-
-[[package]]
-name = "tracing"
-version = "0.1.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
-dependencies = [
- "cfg-if",
- "pin-project-lite",
- "tracing-attributes",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-attributes"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "tracing-core"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f"
-dependencies = [
- "lazy_static",
-]
-
-[[package]]
-name = "try-lock"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
-
-[[package]]
-name = "typenum"
-version = "1.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
-dependencies = [
- "tinyvec",
-]
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
-
-[[package]]
-name = "untrusted"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "want"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
-dependencies = [
- "log",
- "try-lock",
-]
-
-[[package]]
-name = "wasi"
-version = "0.10.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.81"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.81"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
-dependencies = [
- "bumpalo",
- "lazy_static",
- "log",
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.81"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.81"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.81"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
-
-[[package]]
-name = "web-sys"
-version = "0.3.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "webpki"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
-dependencies = [
- "ring",
- "untrusted",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-util"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/rust_ref/Cargo.toml b/rust_ref/Cargo.toml
deleted file mode 100644
index 226a20d6..00000000
--- a/rust_ref/Cargo.toml
+++ /dev/null
@@ -1,36 +0,0 @@
-[package]
-name = "pgcat"
-version = "0.6.0-alpha1"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-tokio = { version = "1", features = ["full"] }
-bytes = "1"
-md-5 = "0.10"
-bb8 = "0.7"
-async-trait = "0.1"
-rand = "0.8"
-chrono = "0.4"
-sha-1 = "0.10"
-toml = "0.5"
-serde = "1"
-serde_derive = "1"
-regex = "1"
-num_cpus = "1"
-once_cell = "1"
-sqlparser = "0.14"
-log = "0.4"
-arc-swap = "1"
-env_logger = "0.9"
-parking_lot = "0.11"
-hmac = "0.12"
-sha2 = "0.10"
-base64 = "0.13"
-stringprep = "0.1"
-tokio-rustls = "0.23"
-rustls-pemfile = "1"
-hyper = { version = "0.14", features = ["full"] }
-phf = { version = "0.10", features = ["macros"] }
-exitcode = "1.1.2"
diff --git a/rust_ref/Dockerfile b/rust_ref/Dockerfile
deleted file mode 100644
index ec29182a..00000000
--- a/rust_ref/Dockerfile
+++ /dev/null
@@ -1,11 +0,0 @@
-FROM rust:1 AS builder
-COPY . /app
-WORKDIR /app
-RUN cargo build --release
-
-FROM debian:bullseye-slim
-COPY --from=builder /app/target/release/pgcat /usr/bin/pgcat
-COPY --from=builder /app/pgcat.toml /etc/pgcat/pgcat.toml
-WORKDIR /etc/pgcat
-ENV RUST_LOG=info
-CMD ["pgcat"]
diff --git a/rust_ref/Dockerfile.ci b/rust_ref/Dockerfile.ci
deleted file mode 100644
index 8f8ab945..00000000
--- a/rust_ref/Dockerfile.ci
+++ /dev/null
@@ -1,8 +0,0 @@
-FROM cimg/rust:1.62.0
-RUN sudo apt-get update && \
-	sudo apt-get install -y psmisc postgresql-contrib-12 postgresql-client-12 ruby ruby-dev libpq-dev python3 python3-pip lcov llvm-11 && \
-	sudo apt-get upgrade curl
-RUN cargo install cargo-binutils rustfilt && \
-	rustup component add llvm-tools-preview
-RUN pip3 install psycopg2 && \
-	sudo gem install bundler
diff --git a/rust_ref/LICENSE b/rust_ref/LICENSE
deleted file mode 100644
index 5cd12617..00000000
--- a/rust_ref/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2022 Lev Kokotov <lev@levthe.dev>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/rust_ref/README.md b/rust_ref/README.md
deleted file mode 100644
index 8d4c77fa..00000000
--- a/rust_ref/README.md
+++ /dev/null
@@ -1,512 +0,0 @@
-# PgCat
-
-[![CircleCI](https://circleci.com/gh/levkk/pgcat/tree/main.svg?style=svg)](https://circleci.com/gh/levkk/pgcat/tree/main)
-
-![PgCat](./pgcat3.png)
-
-PostgreSQL pooler (like PgBouncer) with sharding, load balancing and failover support.
-
-**Beta**: looking for beta testers, see [#35](https://github.com/levkk/pgcat/issues/35).
-
-## Features
-| **Feature**                    | **Status**                  | **Comments**                                                                                                                                          |
-|--------------------------------|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Transaction pooling            | :white_check_mark:          | Identical to PgBouncer.                                                                                                                               |
-| Session pooling                | :white_check_mark:          | Identical to PgBouncer.                                                                                                                               |
-| `COPY` support                 | :white_check_mark:          | Both `COPY TO` and `COPY FROM` are supported.                                                                                                         |
-| Query cancellation             | :white_check_mark:          | Supported both in transaction and session pooling modes.                                                                                              |
-| Load balancing of read queries | :white_check_mark:          | Using random between replicas. Primary is included when `primary_reads_enabled` is enabled (default).                                            |
-| Sharding                       | :white_check_mark:          | Transactions are sharded using `SET SHARD TO` and `SET SHARDING KEY TO` syntax extensions; see examples below.                                        |
-| Failover                       | :white_check_mark:          | Replicas are tested with a health check. If a health check fails, remaining replicas are attempted; see below for algorithm description and examples. |
-| Statistics                     | :white_check_mark:          | Statistics available in the admin database (`pgcat` and `pgbouncer`) with `SHOW STATS`, `SHOW POOLS` and others.                                      |
-| Live configuration reloading   | :white_check_mark:          | Reload supported settings with a `SIGHUP` to the process, e.g. `kill -s SIGHUP $(pgrep pgcat)` or `RELOAD` query issued to the admin database.        |
-| Client authentication          | :white_check_mark: :wrench: | MD5 password authentication is supported, SCRAM is on the roadmap; one user is used to connect to Postgres with both SCRAM and MD5 supported.         |
-| Admin database                 | :white_check_mark:          | The admin database, similar to PgBouncer's, allows to query for statistics and reload the configuration.                                              |
-
-## Deployment
-
-See `Dockerfile` for example deployment using Docker. The pooler is configured to spawn 4 workers so 4 CPUs are recommended for optimal performance. That setting can be adjusted to spawn as many (or as little) workers as needed.
-
-For quick local example, use the Docker Compose environment provided:
-
-```bash
-docker-compose up
-
-# In a new terminal:
-psql -h 127.0.0.1 -p 6432 -c 'SELECT 1'
-```
-
-### Config
-
-| **Name**                     | **Description**                                                                                                                            | **Examples**                     |
-|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|
-| **`general`**                |                                                                                                                                            |                                  |
-| `host`                       | The pooler will run on this host, 0.0.0.0 means accessible from everywhere.                                                                | `0.0.0.0`                        |
-| `port`                       | The pooler will run on this port.                                                                                                          | `6432`                           |
-| `enable_prometheus_exporter` | Enable prometheus exporter which will export metrics in prometheus exposition format.                                                      | `true`                           |
-| `prometheus_exporter_port`   | Port at which prometheus exporter listens on.                                                                                              | `9930`                           |
-| `pool_size`                  | Maximum allowed server connections per pool. Pools are separated for each user/shard/server role. The connections are allocated as needed. | `15`                             |
-| `pool_mode`                  | The pool mode to use, i.e. `session` or `transaction`.                                                                                     | `transaction`                    |
-| `connect_timeout`            | Maximum time to establish a connection to a server (milliseconds). If reached, the server is banned and the next target is attempted.      | `5000`                           |
-| `healthcheck_timeout`        | Maximum time to pass a health check (`SELECT 1`, milliseconds). If reached, the server is banned and the next target is attempted.         | `1000`                           |
-| `shutdown_timeout`           | Maximum time to give clients during shutdown before forcibly killing client connections (ms).                                              | `60000`                          |
-| `healthcheck_delay`          | How long to keep connection available for immediate re-use, without running a healthcheck query on it                                      | `30000`                          |
-| `ban_time`                   | Ban time for a server (seconds). It won't be allowed to serve transactions until the ban expires; failover targets will be used instead.   | `60`                             |
-| `autoreload`                 | Enable auto-reload of config after fixed time-interval.                                                                                    | `false`                          |
-|                              |                                                                                                                                            |                                  |
-| **`user`**                   |                                                                                                                                            |                                  |
-| `name`                       | The user name.                                                                                                                             | `sharding_user`                  |
-| `password`                   | The user password in plaintext.                                                                                                            | `hunter2`                        |
-|                              |                                                                                                                                            |                                  |
-| **`shards`**                 | Shards are numerically numbered starting from 0; the order in the config is preserved by the pooler to route queries accordingly.          | `[shards.0]`                     |
-| `servers`                    | List of servers to connect to and their roles. A server is: `[host, port, role]`, where `role` is either `primary` or `replica`.           | `["127.0.0.1", 5432, "primary"]` |
-| `database`                   | The name of the database to connect to. This is the same on all servers that are part of one shard.                                        |                                  |
-|                              |                                                                                                                                            |                                  |
-| **`query_router`**           |                                                                                                                                            |                                  |
-| `default_role`               | Traffic is routed to this role by default (random), unless the client specifies otherwise. Default is `any`, for any role available.  | `any`, `primary`, `replica`      |
-| `query_parser_enabled`       | Enable the query parser which will inspect incoming queries and route them to a primary or replicas.                                       | `false`                          |
-| `primary_reads_enabled`      | Enable this to allow read queries on the primary; otherwise read queries are routed to the replicas.                                       | `true`                           |
-
-## Local development
-
-1. Install Rust (latest stable will work great).
-2. `cargo build --release` (to get better benchmarks).
-3. Change the config in `pgcat.toml` to fit your setup (optional given next step).
-4. Install Postgres and run `psql -f tests/sharding/query_routing_setup.sql` (user/password may be required depending on your setup)
-5. `RUST_LOG=info cargo run --release` You're ready to go!
-
-### Tests
-
-Quickest way to test your changes is to use pgbench:
-
-```
-pgbench -i -h 127.0.0.1 -p 6432 && \
-pgbench -t 1000 -p 6432 -h 127.0.0.1 --protocol simple && \
-pgbench -t 1000 -p 6432 -h 127.0.0.1 --protocol extended
-```
-
-See [sharding README](./tests/sharding/README.md) for sharding logic testing.
-
-Run `cargo test` to run Rust tests.
-
-Run the following commands to run Integration tests locally.
-```
-cd tests/docker/
-docker compose up --exit-code-from main # This will also produce coverage report under ./cov/
-```
-
-| **Feature**           | **Tested in CI**   | **Tested manually** | **Comments**                                                                                                             |
-|-----------------------|--------------------|---------------------|--------------------------------------------------------------------------------------------------------------------------|
-| Transaction pooling   | :white_check_mark: | :white_check_mark:  | Used by default for all tests.                                                                                           |
-| Session pooling       | :white_check_mark: | :white_check_mark:  | Tested by running pgbench with `--protocol prepared` which only works in session mode.                                   |
-| `COPY`                | :white_check_mark: | :white_check_mark:  | `pgbench -i` uses `COPY`. `COPY FROM` is tested as well.                                                                 |
-| Query cancellation    | :white_check_mark: | :white_check_mark:  | `psql -c 'SELECT pg_sleep(1000);'` and press `Ctrl-C`.                                                                   |
-| Load balancing        | :white_check_mark: | :white_check_mark:  | We could test this by emitting statistics for each replica and compare them.                                             |
-| Failover              | :white_check_mark: | :white_check_mark:  | Misconfigure a replica in `pgcat.toml` and watch it forward queries to spares. CI testing is using Toxiproxy.            |
-| Sharding              | :white_check_mark: | :white_check_mark:  | See `tests/sharding` and `tests/ruby` for an Rails/ActiveRecord example.                                                 |
-| Statistics            | :white_check_mark: | :white_check_mark:  | Query the admin database with `psql -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW STATS'`.                                  |
-| Live config reloading | :white_check_mark: | :white_check_mark:  | Run `kill -s SIGHUP $(pgrep pgcat)` and watch the config reload.                                                         |
-
-## Usage
-
-### Session mode
-In session mode, a client talks to one server for the duration of the connection. Prepared statements, `SET`, and advisory locks are supported. In terms of supported features, there is very little if any difference between session mode and talking directly to the server.
-
-To use session mode, change `pool_mode = "session"`.
-
-### Transaction mode
-In transaction mode, a client talks to one server for the duration of a single transaction; once it's over, the server is returned to the pool. Prepared statements, `SET`, and advisory locks are not supported; alternatives are to use `SET LOCAL` and `pg_advisory_xact_lock` which are scoped to the transaction.
-
-This mode is enabled by default.
-
-### Load balancing of read queries
-All queries are load balanced against the configured servers using the random algorithm. The most straight forward configuration example would be to put this pooler in front of several replicas and let it load balance all queries.
-
-If the configuration includes a primary and replicas, the queries can be separated with the built-in query parser. The query parser will interpret the query and route all `SELECT` queries to a replica, while all other queries including explicit transactions will be routed to the primary.
-
-The query parser is disabled by default.
-
-#### Query parser
-The query parser will do its best to determine where the query should go, but sometimes that's not possible. In that case, the client can select which server it wants using this custom SQL syntax:
-
-```sql
--- To talk to the primary for the duration of the next transaction:
-SET SERVER ROLE TO 'primary';
-
--- To talk to the replica for the duration of the next transaction:
-SET SERVER ROLE TO 'replica';
-
--- Let the query parser decide
-SET SERVER ROLE TO 'auto';
-
--- Pick any server at random
-SET SERVER ROLE TO 'any';
-
--- Reset to default configured settings
-SET SERVER ROLE TO 'default';
-```
-
-The setting will persist until it's changed again or the client disconnects.
-
-By default, all queries are routed to the first available server; `default_role` setting controls this behavior.
-
-### Failover
-All servers are checked with a `SELECT 1` query before being given to a client. If the server is not reachable, it will be banned and cannot serve any more transactions for the duration of the ban. The queries are routed to the remaining servers. If all servers become banned, the ban list is cleared: this is a safety precaution against false positives. The primary can never be banned.
-
-The ban time can be changed with `ban_time`. The default is 60 seconds.
-
-Failover behavior can get pretty interesting (read complex) when multiple configurations and factors are involved. The table below will try to explain what PgCat does in each scenario:
-
-| **Query**                 | **`SET SERVER ROLE TO`** | **`query_parser_enabled`** | **`primary_reads_enabled`** | **Target state** | **Outcome**                                                                                                                                                          |
-|---------------------------|--------------------------|----------------------------|-----------------------------|------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Read query, i.e. `SELECT` | unset (any)              | false                      | false                       | up               | Query is routed to the first instance in the random loop.                                                                                                       |
-| Read query                | unset (any)              | true                       | false                       | up               | Query is routed to the first replica instance in the random loop.                                                                                               |
-| Read query                | unset (any)              | true                       | true                        | up               | Query is routed to the first instance in the random loop.                                                                                                       |
-| Read query                | replica                  | false                      | false                       | up               | Query is routed to the first replica instance in the random loop.                                                                                               |
-| Read query                | primary                  | false                      | false                       | up               | Query is routed to the primary.                                                                                                                                      |
-| Read query                | unset (any)              | false                      | false                       | down             | First instance is banned for reads. Next target in the random loop is attempted.                                                                                |
-| Read query                | unset (any)              | true                       | false                       | down             | First replica instance is banned. Next replica instance is attempted in the random loop.                                                                        |
-| Read query                | unset (any)              | true                       | true                        | down             | First instance (even if primary) is banned for reads. Next instance is attempted in the random loop.                                                            |
-| Read query                | replica                  | false                      | false                       | down             | First replica instance is banned. Next replica instance is attempted in the random loop.                                                                        |
-| Read query                | primary                  | false                      | false                       | down             | The query is attempted against the primary and fails. The client receives an error.                                                                                  |
-|                           |                          |                            |                             |                  |                                                                                                                                                                      |
-| Write query e.g. `INSERT` | unset (any)              | false                      | false                       | up               | The query is attempted against the first available instance in the random loop. If the instance is a replica, the query fails and the client receives an error. |
-| Write query               | unset (any)              | true                       | false                       | up               | The query is routed to the primary.                                                                                                                                  |
-| Write query               | unset (any)              | true                       | true                        | up               | The query is routed to the primary.                                                                                                                                  |
-| Write query               | primary                  | false                      | false                       | up               | The query is routed to the primary.                                                                                                                                  |
-| Write query               | replica                  | false                      | false                       | up               | The query is routed to the replica and fails. The client receives an error.                                                                                          |
-| Write query               | unset (any)              | true                       | false                       | down             | The query is routed to the primary and fails. The client receives an error.                                                                                          |
-| Write query               | unset (any)              | true                       | true                        | down             | The query is routed to the primary and fails. The client receives an error.                                                                                          |
-| Write query               | primary                  | false                      | false                       | down             | The query is routed to the primary and fails. The client receives an error.                                                                                          |
-|                           |                          |                            |                             |                  |                                                                                                                                                                      |
-
-### Sharding
-We use the `PARTITION BY HASH` hashing function, the same as used by Postgres for declarative partitioning. This allows to shard the database using Postgres partitions and place the partitions on different servers (shards). Both read and write queries can be routed to the shards using this pooler.
-
-To route queries to a particular shard, we use this custom SQL syntax:
-
-```sql
--- To talk to a shard explicitely
-SET SHARD TO '1';
-
--- To let the pooler choose based on a value
-SET SHARDING KEY TO '1234';
-```
-
-The active shard will last until it's changed again or the client disconnects. By default, the queries are routed to shard 0.
-
-For hash function implementation, see `src/sharding.rs` and `tests/sharding/partition_hash_test_setup.sql`.
-
-#### ActiveRecord/Rails
-
-```ruby
-class User < ActiveRecord::Base
-end
-
-# Metadata will be fetched from shard 0
-ActiveRecord::Base.establish_connection
-
-# Grab a bunch of users from shard 1
-User.connection.execute "SET SHARD TO '1'"
-User.take(10)
-
-# Using id as the sharding key
-User.connection.execute "SET SHARDING KEY TO '1234'"
-User.find_by_id(1234)
-
-# Using geographical sharding
-User.connection.execute "SET SERVER ROLE TO 'primary'"
-User.connection.execute "SET SHARDING KEY TO '85'"
-User.create(name: "test user", email: "test@example.com", zone_id: 85)
-
-# Let the query parser figure out where the query should go.
-# We are still on shard = hash(85) % shards.
-User.connection.execute "SET SERVER ROLE TO 'auto'"
-User.find_by_email("test@example.com")
-```
-
-#### Raw SQL
-
-```sql
--- Grab a bunch of users from shard 1
-SET SHARD TO '1';
-SELECT * FROM users LIMT 10;
-
--- Find by id
-SET SHARDING KEY TO '1234';
-SELECT * FROM USERS WHERE id = 1234;
-
--- Writing in a primary/replicas configuration.
-SET SHARDING ROLE TO 'primary';
-SET SHARDING KEY TO '85';
-INSERT INTO users (name, email, zome_id) VALUES ('test user', 'test@example.com', 85);
-
-SET SERVER ROLE TO 'auto'; -- let the query router figure out where the query should go
-SELECT * FROM users WHERE email = 'test@example.com'; -- shard setting lasts until set again; we are reading from the primary
-```
-
-### Statistics reporting
-
-The stats are very similar to what Pgbouncer reports and the names are kept to be comparable. They are accessible by querying the admin database `pgcat`, and `pgbouncer` for compatibility.
-
-```
-psql -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW DATABASES'
-```
-
-### Live configuration reloading
-
-The config can be reloaded by sending a `kill -s SIGHUP` to the process or by querying `RELOAD` to the admin database. Not all settings are currently supported by live reload:
-
-| **Config**              | **Requires restart** |
-|-------------------------|----------------------|
-| `host`                  | yes                  |
-| `port`                  | yes                  |
-| `pool_mode`             | no                   |
-| `connect_timeout`       | yes                  |
-| `healthcheck_timeout`   | no                   |
-| `shutdown_timeout`      | no                   |
-| `healthcheck_delay`     | no                   |
-| `ban_time`              | no                   |
-| `user`                  | yes                  |
-| `shards`                | yes                  |
-| `default_role`          | no                   |
-| `primary_reads_enabled` | no                   |
-| `query_parser_enabled`  | no                   |
-
-
-## Benchmarks
-
-You can setup PgBench locally through PgCat:
-
-```
-pgbench -h 127.0.0.1 -p 6432 -i
-```
-
-Coincidenly, this uses `COPY` so you can test if that works. Additionally, we'll be running the following PgBench configurations:
-
-1. 16 clients, 2 threads
-2. 32 clients, 2 threads
-3. 64 clients, 2 threads
-4. 128 clients, 2 threads
-
-All queries will be `SELECT` only (`-S`) just so disks don't get in the way, since the dataset will be effectively all in RAM.
-
-My setup:
-
-- 8 cores, 16 hyperthreaded (AMD Ryzen 5800X)
-- 32GB RAM (doesn't matter for this benchmark, except to prove that Postgres will fit the whole dataset into RAM)
-
-### PgBouncer
-
-#### Config
-
-```ini
-[databases]
-shard0 = host=localhost port=5432 user=sharding_user password=sharding_user
-
-[pgbouncer]
-pool_mode = transaction
-max_client_conn = 1000
-```
-
-Everything else stays default.
-
-#### Runs
-
-
-```
-$ pgbench -t 1000 -c 16 -j 2 -p 6432 -h 127.0.0.1 -S --protocol extended shard0
-
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 16
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 16000/16000
-latency average = 0.155 ms
-tps = 103417.377469 (including connections establishing)
-tps = 103510.639935 (excluding connections establishing)
-
-
-$ pgbench -t 1000 -c 32 -j 2 -p 6432 -h 127.0.0.1 -S --protocol extended shard0
-
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 32
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 32000/32000
-latency average = 0.290 ms
-tps = 110325.939785 (including connections establishing)
-tps = 110386.513435 (excluding connections establishing)
-
-
-$ pgbench -t 1000 -c 64 -j 2 -p 6432 -h 127.0.0.1 -S --protocol extended shard0
-
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 64
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 64000/64000
-latency average = 0.692 ms
-tps = 92470.427412 (including connections establishing)
-tps = 92618.389350 (excluding connections establishing)
-
-$ pgbench -t 1000 -c 128 -j 2 -p 6432 -h 127.0.0.1 -S --protocol extended shard0
-
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 128
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 128000/128000
-latency average = 1.406 ms
-tps = 91013.429985 (including connections establishing)
-tps = 91067.583928 (excluding connections establishing)
-```
-
-### PgCat
-
-#### Config
-
-The only thing that matters here is the number of workers in the Tokio pool. Make sure to set it to < than the number of your CPU cores.
-Also account for hyper-threading, so if you have that, take the number you got above and divide it by two, that way only "real" cores serving
-requests.
-
-My setup is 16 threads, 8 cores (`htop` shows as 16 CPUs), so I set the `max_workers` in Tokio to 4. Too many, and it starts conflicting with PgBench
-which is also running on the same system.
-
-#### Runs
-
-
-```
-$ pgbench -t 1000 -c 16 -j 2 -p 6432 -h 127.0.0.1 -S --protocol extended
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 16
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 16000/16000
-latency average = 0.164 ms
-tps = 97705.088232 (including connections establishing)
-tps = 97872.216045 (excluding connections establishing)
-
-
-$ pgbench -t 1000 -c 32 -j 2 -p 6432 -h 127.0.0.1 -S --protocol extended
-
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 32
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 32000/32000
-latency average = 0.288 ms
-tps = 111300.488119 (including connections establishing)
-tps = 111413.107800 (excluding connections establishing)
-
-
-$ pgbench -t 1000 -c 64 -j 2 -p 6432 -h 127.0.0.1 -S --protocol extended
-
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 64
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 64000/64000
-latency average = 0.556 ms
-tps = 115190.496139 (including connections establishing)
-tps = 115247.521295 (excluding connections establishing)
-
-$ pgbench -t 1000 -c 128 -j 2 -p 6432 -h 127.0.0.1 -S --protocol extended
-
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 128
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 128000/128000
-latency average = 1.135 ms
-tps = 112770.562239 (including connections establishing)
-tps = 112796.502381 (excluding connections establishing)
-```
-
-### Direct Postgres
-
-Always good to have a base line.
-
-#### Runs
-
-```
-$ pgbench -t 1000 -c 16 -j 2 -p 5432 -h 127.0.0.1 -S --protocol extended shard0
-Password:
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 16
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 16000/16000
-latency average = 0.115 ms
-tps = 139443.955722 (including connections establishing)
-tps = 142314.859075 (excluding connections establishing)
-
-$ pgbench -t 1000 -c 32 -j 2 -p 5432 -h 127.0.0.1 -S --protocol extended shard0
-Password:
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 32
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 32000/32000
-latency average = 0.212 ms
-tps = 150644.840891 (including connections establishing)
-tps = 152218.499430 (excluding connections establishing)
-
-$ pgbench -t 1000 -c 64 -j 2 -p 5432 -h 127.0.0.1 -S --protocol extended shard0
-Password:
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 64
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 64000/64000
-latency average = 0.420 ms
-tps = 152517.663404 (including connections establishing)
-tps = 153319.188482 (excluding connections establishing)
-
-$ pgbench -t 1000 -c 128 -j 2 -p 5432 -h 127.0.0.1 -S --protocol extended shard0
-Password:
-starting vacuum...end.
-transaction type: <builtin: select only>
-scaling factor: 1
-query mode: extended
-number of clients: 128
-number of threads: 2
-number of transactions per client: 1000
-number of transactions actually processed: 128000/128000
-latency average = 0.854 ms
-tps = 149818.594087 (including connections establishing)
-tps = 150200.603049 (excluding connections establishing)
-```
diff --git a/rust_ref/docker-compose.yml b/rust_ref/docker-compose.yml
deleted file mode 100644
index 96d1f395..00000000
--- a/rust_ref/docker-compose.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-version: "3"
-services:
-  postgres:
-    image: postgres:14
-    environment:
-      POSTGRES_PASSWORD: postgres
-      POSTGRES_HOST_AUTH_METHOD: md5
-  pgcat:
-    build: .
-    command:
-      - "pgcat"
-      - "/etc/pgcat/pgcat.toml"
-    volumes:
-      - "${PWD}/examples/docker/pgcat.toml:/etc/pgcat/pgcat.toml"
-    ports:
-      - "6432:6432"
-      - "9930:9930"
diff --git a/rust_ref/examples/docker/pgcat.toml b/rust_ref/examples/docker/pgcat.toml
deleted file mode 100644
index 85a3f466..00000000
--- a/rust_ref/examples/docker/pgcat.toml
+++ /dev/null
@@ -1,147 +0,0 @@
-#
-# PgCat config example.
-#
-
-#
-# General pooler settings
-[general]
-# What IP to run on, 0.0.0.0 means accessible from everywhere.
-host = "0.0.0.0"
-
-# Port to run on, same as PgBouncer used in this example.
-port = 6432
-
-# Whether to enable prometheus exporter or not.
-enable_prometheus_exporter = true
-
-# Port at which prometheus exporter listens on.
-prometheus_exporter_port = 9930
-
-# How long to wait before aborting a server connection (ms).
-connect_timeout = 5000
-
-# How much time to give `SELECT 1` health check query to return with a result (ms).
-healthcheck_timeout = 1000
-
-# How long to keep connection available for immediate re-use, without running a healthcheck query on it
-healthcheck_delay = 30000
-
-# How much time to give clients during shutdown before forcibly killing client connections (ms).
-shutdown_timeout = 60000
-
-# For how long to ban a server if it fails a health check (seconds).
-ban_time = 60 # seconds
-
-# Reload config automatically if it changes.
-autoreload = false
-
-# TLS
-# tls_certificate = "server.cert"
-# tls_private_key = "server.key"
-
-# Credentials to access the virtual administrative database (pgbouncer or pgcat)
-# Connecting to that database allows running commands like `SHOW POOLS`, `SHOW DATABASES`, etc..
-admin_username = "postgres"
-admin_password = "postgres"
-
-# pool
-# configs are structured as pool.<pool_name>
-# the pool_name is what clients use as database name when connecting
-# For the example below a client can connect using "postgres://sharding_user:sharding_user@pgcat_host:pgcat_port/sharded"
-[pools.sharded]
-# Pool mode (see PgBouncer docs for more).
-# session: one server connection per connected client
-# transaction: one server connection per client transaction
-pool_mode = "transaction"
-
-# If the client doesn't specify, route traffic to
-# this role by default.
-#
-# any: round-robin between primary and replicas,
-# replica: round-robin between replicas only without touching the primary,
-# primary: all queries go to the primary unless otherwise specified.
-default_role = "any"
-
-# Query parser. If enabled, we'll attempt to parse
-# every incoming query to determine if it's a read or a write.
-# If it's a read query, we'll direct it to a replica. Otherwise, if it's a write,
-# we'll direct it to the primary.
-query_parser_enabled = true
-
-# If the query parser is enabled and this setting is enabled, the primary will be part of the pool of databases used for
-# load balancing of read queries. Otherwise, the primary will only be used for write
-# queries. The primary can always be explicitely selected with our custom protocol.
-primary_reads_enabled = true
-
-# So what if you wanted to implement a different hashing function,
-# or you've already built one and you want this pooler to use it?
-#
-# Current options:
-#
-# pg_bigint_hash: PARTITION BY HASH (Postgres hashing function)
-# sha1: A hashing function based on SHA1
-#
-sharding_function = "pg_bigint_hash"
-
-# Credentials for users that may connect to this cluster
-[pools.sharded.users.0]
-username = "postgres"
-password = "postgres"
-# Maximum number of server connections that can be established for this user
-# The maximum number of connection from a single Pgcat process to any database in the cluster
-# is the sum of pool_size across all users.
-pool_size = 9
-
-# Maximum query duration. Dangerous, but protects against DBs that died in a non-obvious way.
-statement_timeout = 0
-
-[pools.sharded.users.1]
-username = "postgres"
-password = "postgres"
-pool_size = 21
-statement_timeout = 15000
-
-# Shard 0
-[pools.sharded.shards.0]
-# [ host, port, role ]
-servers = [
-    [ "postgres", 5432, "primary" ],
-    [ "postgres", 5432, "replica" ]
-]
-# Database name (e.g. "postgres")
-database = "postgres"
-
-[pools.sharded.shards.1]
-servers = [
-    [ "postgres", 5432, "primary" ],
-    [ "postgres", 5432, "replica" ],
-]
-database = "postgres"
-
-[pools.sharded.shards.2]
-servers = [
-    [ "postgres", 5432, "primary" ],
-    [ "postgres", 5432, "replica" ],
-]
-database = "postgres"
-
-
-[pools.simple_db]
-pool_mode = "session"
-default_role = "primary"
-query_parser_enabled = true
-primary_reads_enabled = true
-sharding_function = "pg_bigint_hash"
-
-[pools.simple_db.users.0]
-username = "postgres"
-password = "postgres"
-pool_size = 5
-statement_timeout = 0
-
-[pools.simple_db.shards.0]
-servers = [
-    [ "postgres", 5432, "primary" ],
-    [ "postgres", 5432, "replica" ]
-]
-database = "postgres"
diff --git a/rust_ref/pgcat.toml b/rust_ref/pgcat.toml
deleted file mode 100644
index 9125afd5..00000000
--- a/rust_ref/pgcat.toml
+++ /dev/null
@@ -1,147 +0,0 @@
-#
-# PgCat config example.
-#
-
-#
-# General pooler settings
-[general]
-# What IP to run on, 0.0.0.0 means accessible from everywhere.
-host = "0.0.0.0"
-
-# Port to run on, same as PgBouncer used in this example.
-port = 6432
-
-# Whether to enable prometheus exporter or not.
-enable_prometheus_exporter = true
-
-# Port at which prometheus exporter listens on.
-prometheus_exporter_port = 9930
-
-# How long to wait before aborting a server connection (ms).
-connect_timeout = 5000
-
-# How much time to give the health check query to return with a result (ms).
-healthcheck_timeout = 1000
-
-# How long to keep connection available for immediate re-use, without running a healthcheck query on it
-healthcheck_delay = 30000
-
-# How much time to give clients during shutdown before forcibly killing client connections (ms).
-shutdown_timeout = 60000
-
-# For how long to ban a server if it fails a health check (seconds).
-ban_time = 60 # seconds
-
-# Reload config automatically if it changes.
-autoreload = false
-
-# TLS
-# tls_certificate = "server.cert"
-# tls_private_key = "server.key"
-
-# Credentials to access the virtual administrative database (pgbouncer or pgcat)
-# Connecting to that database allows running commands like `SHOW POOLS`, `SHOW DATABASES`, etc..
-admin_username = "admin_user"
-admin_password = "admin_pass"
-
-# pool
-# configs are structured as pool.<pool_name>
-# the pool_name is what clients use as database name when connecting
-# For the example below a client can connect using "postgres://sharding_user:sharding_user@pgcat_host:pgcat_port/sharded_db"
-[pools.sharded_db]
-# Pool mode (see PgBouncer docs for more).
-# session: one server connection per connected client
-# transaction: one server connection per client transaction
-pool_mode = "transaction"
-
-# If the client doesn't specify, route traffic to
-# this role by default.
-#
-# any: round-robin between primary and replicas,
-# replica: round-robin between replicas only without touching the primary,
-# primary: all queries go to the primary unless otherwise specified.
-default_role = "any"
-
-# Query parser. If enabled, we'll attempt to parse
-# every incoming query to determine if it's a read or a write.
-# If it's a read query, we'll direct it to a replica. Otherwise, if it's a write,
-# we'll direct it to the primary.
-query_parser_enabled = true
-
-# If the query parser is enabled and this setting is enabled, the primary will be part of the pool of databases used for
-# load balancing of read queries. Otherwise, the primary will only be used for write
-# queries. The primary can always be explicitly selected with our custom protocol.
-primary_reads_enabled = true
-
-# So what if you wanted to implement a different hashing function,
-# or you've already built one and you want this pooler to use it?
-#
-# Current options:
-#
-# pg_bigint_hash: PARTITION BY HASH (Postgres hashing function)
-# sha1: A hashing function based on SHA1
-#
-sharding_function = "pg_bigint_hash"
-
-# Credentials for users that may connect to this cluster
-[pools.sharded_db.users.0]
-username = "sharding_user"
-password = "sharding_user"
-# Maximum number of server connections that can be established for this user
-# The maximum number of connection from a single Pgcat process to any database in the cluster
-# is the sum of pool_size across all users.
-pool_size = 9
-
-# Maximum query duration. Dangerous, but protects against DBs that died in a non-obvious way.
-statement_timeout = 0
-
-[pools.sharded_db.users.1]
-username = "other_user"
-password = "other_user"
-pool_size = 21
-statement_timeout = 15000
-
-# Shard 0
-[pools.sharded_db.shards.0]
-# [ host, port, role ]
-servers = [
-    [ "127.0.0.1", 5432, "primary" ],
-    [ "localhost", 5432, "replica" ]
-]
-# Database name (e.g. "postgres")
-database = "shard0"
-
-[pools.sharded_db.shards.1]
-servers = [
-    [ "127.0.0.1", 5432, "primary" ],
-    [ "localhost", 5432, "replica" ],
-]
-database = "shard1"
-
-[pools.sharded_db.shards.2]
-servers = [
-    [ "127.0.0.1", 5432, "primary" ],
-    [ "localhost", 5432, "replica" ],
-]
-database = "shard2"
-
-
-[pools.simple_db]
-pool_mode = "session"
-default_role = "primary"
-query_parser_enabled = true
-primary_reads_enabled = true
-sharding_function = "pg_bigint_hash"
-
-[pools.simple_db.users.0]
-username = "simple_user"
-password = "simple_user"
-pool_size = 5
-statement_timeout = 0
-
-[pools.simple_db.shards.0]
-servers = [
-    [ "127.0.0.1", 5432, "primary" ],
-    [ "localhost", 5432, "replica" ]
-]
-database = "some_db"
diff --git a/rust_ref/src/admin.rs b/rust_ref/src/admin.rs
deleted file mode 100644
index 4576d168..00000000
--- a/rust_ref/src/admin.rs
+++ /dev/null
@@ -1,441 +0,0 @@
-/// Admin database.
-use bytes::{Buf, BufMut, BytesMut};
-use log::{info, trace};
-use std::collections::HashMap;
-
-use crate::config::{get_config, reload_config, VERSION};
-use crate::errors::Error;
-use crate::messages::*;
-use crate::pool::get_all_pools;
-use crate::stats::get_stats;
-use crate::ClientServerMap;
-
-pub fn generate_server_info_for_admin() -> BytesMut {
-    let mut server_info = BytesMut::new();
-
-    server_info.put(server_paramater_message("application_name", ""));
-    server_info.put(server_paramater_message("client_encoding", "UTF8"));
-    server_info.put(server_paramater_message("server_encoding", "UTF8"));
-    server_info.put(server_paramater_message("server_version", VERSION));
-    server_info.put(server_paramater_message("DateStyle", "ISO, MDY"));
-
-    return server_info;
-}
-
-/// Handle admin client.
-pub async fn handle_admin<T>(
-    stream: &mut T,
-    mut query: BytesMut,
-    client_server_map: ClientServerMap,
-) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let code = query.get_u8() as char;
-
-    if code != 'Q' {
-        return Err(Error::ProtocolSyncError);
-    }
-
-    let len = query.get_i32() as usize;
-    let query = String::from_utf8_lossy(&query[..len - 5])
-        .to_string()
-        .to_ascii_uppercase();
-
-    trace!("Admin query: {}", query);
-
-    let query_parts: Vec<&str> = query.trim_end_matches(';').split_whitespace().collect();
-
-    match query_parts[0] {
-        "RELOAD" => {
-            trace!("RELOAD");
-            reload(stream, client_server_map).await
-        }
-        "SET" => {
-            trace!("SET");
-            ignore_set(stream).await
-        }
-        "SHOW" => match query_parts[1] {
-            "CONFIG" => {
-                trace!("SHOW CONFIG");
-                show_config(stream).await
-            }
-            "DATABASES" => {
-                trace!("SHOW DATABASES");
-                show_databases(stream).await
-            }
-            "LISTS" => {
-                trace!("SHOW LISTS");
-                show_lists(stream).await
-            }
-            "POOLS" => {
-                trace!("SHOW POOLS");
-                show_pools(stream).await
-            }
-            "STATS" => {
-                trace!("SHOW STATS");
-                show_stats(stream).await
-            }
-            "VERSION" => {
-                trace!("SHOW VERSION");
-                show_version(stream).await
-            }
-            _ => error_response(stream, "Unsupported SHOW query against the admin database").await,
-        },
-        _ => error_response(stream, "Unsupported query against the admin database").await,
-    }
-}
-
-/// Column-oriented statistics.
-async fn show_lists<T>(stream: &mut T) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let stats = get_stats();
-
-    let columns = vec![("list", DataType::Text), ("items", DataType::Int4)];
-
-    let mut users = 1;
-    let mut databases = 1;
-    for (_, pool) in get_all_pools() {
-        databases += pool.databases();
-        users += 1; // One user per pool
-    }
-    let mut res = BytesMut::new();
-    res.put(row_description(&columns));
-    res.put(data_row(&vec![
-        "databases".to_string(),
-        databases.to_string(),
-    ]));
-    res.put(data_row(&vec!["users".to_string(), users.to_string()]));
-    res.put(data_row(&vec!["pools".to_string(), databases.to_string()]));
-    res.put(data_row(&vec![
-        "free_clients".to_string(),
-        stats
-            .keys()
-            .map(|address_id| stats[&address_id]["cl_idle"])
-            .sum::<i64>()
-            .to_string(),
-    ]));
-    res.put(data_row(&vec![
-        "used_clients".to_string(),
-        stats
-            .keys()
-            .map(|address_id| stats[&address_id]["cl_active"])
-            .sum::<i64>()
-            .to_string(),
-    ]));
-    res.put(data_row(&vec![
-        "login_clients".to_string(),
-        "0".to_string(),
-    ]));
-    res.put(data_row(&vec![
-        "free_servers".to_string(),
-        stats
-            .keys()
-            .map(|address_id| stats[&address_id]["sv_idle"])
-            .sum::<i64>()
-            .to_string(),
-    ]));
-    res.put(data_row(&vec![
-        "used_servers".to_string(),
-        stats
-            .keys()
-            .map(|address_id| stats[&address_id]["sv_active"])
-            .sum::<i64>()
-            .to_string(),
-    ]));
-    res.put(data_row(&vec!["dns_names".to_string(), "0".to_string()]));
-    res.put(data_row(&vec!["dns_zones".to_string(), "0".to_string()]));
-    res.put(data_row(&vec!["dns_queries".to_string(), "0".to_string()]));
-    res.put(data_row(&vec!["dns_pending".to_string(), "0".to_string()]));
-
-    res.put(command_complete("SHOW"));
-
-    res.put_u8(b'Z');
-    res.put_i32(5);
-    res.put_u8(b'I');
-
-    write_all_half(stream, res).await
-}
-
-/// Show PgCat version.
-async fn show_version<T>(stream: &mut T) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let mut res = BytesMut::new();
-
-    res.put(row_description(&vec![("version", DataType::Text)]));
-    res.put(data_row(&vec![format!("PgCat {}", VERSION).to_string()]));
-    res.put(command_complete("SHOW"));
-
-    res.put_u8(b'Z');
-    res.put_i32(5);
-    res.put_u8(b'I');
-
-    write_all_half(stream, res).await
-}
-
-/// Show utilization of connection pools for each shard and replicas.
-async fn show_pools<T>(stream: &mut T) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let stats = get_stats();
-
-    let columns = vec![
-        ("database", DataType::Text),
-        ("user", DataType::Text),
-        ("cl_idle", DataType::Numeric),
-        ("cl_active", DataType::Numeric),
-        ("cl_waiting", DataType::Numeric),
-        ("cl_cancel_req", DataType::Numeric),
-        ("sv_active", DataType::Numeric),
-        ("sv_idle", DataType::Numeric),
-        ("sv_used", DataType::Numeric),
-        ("sv_tested", DataType::Numeric),
-        ("sv_login", DataType::Numeric),
-        ("maxwait", DataType::Numeric),
-        ("maxwait_us", DataType::Numeric),
-        ("pool_mode", DataType::Text),
-    ];
-
-    let mut res = BytesMut::new();
-    res.put(row_description(&columns));
-    for (_, pool) in get_all_pools() {
-        let pool_config = &pool.settings;
-        for shard in 0..pool.shards() {
-            for server in 0..pool.servers(shard) {
-                let address = pool.address(shard, server);
-                let stats = match stats.get(&address.id) {
-                    Some(stats) => stats.clone(),
-                    None => HashMap::new(),
-                };
-
-                let mut row = vec![address.name(), pool_config.user.username.clone()];
-
-                for column in &columns[2..columns.len() - 1] {
-                    let value = stats.get(column.0).unwrap_or(&0).to_string();
-                    row.push(value);
-                }
-
-                row.push(pool_config.pool_mode.to_string());
-                res.put(data_row(&row));
-            }
-        }
-    }
-
-    res.put(command_complete("SHOW"));
-
-    // ReadyForQuery
-    res.put_u8(b'Z');
-    res.put_i32(5);
-    res.put_u8(b'I');
-
-    write_all_half(stream, res).await
-}
-
-/// Show shards and replicas.
-async fn show_databases<T>(stream: &mut T) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    // Columns
-    let columns = vec![
-        ("name", DataType::Text),
-        ("host", DataType::Text),
-        ("port", DataType::Text),
-        ("database", DataType::Text),
-        ("force_user", DataType::Text),
-        ("pool_size", DataType::Int4),
-        ("min_pool_size", DataType::Int4),
-        ("reserve_pool", DataType::Int4),
-        ("pool_mode", DataType::Text),
-        ("max_connections", DataType::Int4),
-        ("current_connections", DataType::Int4),
-        ("paused", DataType::Int4),
-        ("disabled", DataType::Int4),
-    ];
-
-    let mut res = BytesMut::new();
-
-    res.put(row_description(&columns));
-
-    for (_, pool) in get_all_pools() {
-        let pool_config = pool.settings.clone();
-        for shard in 0..pool.shards() {
-            let database_name = &pool.address(shard, 0).database;
-            for server in 0..pool.servers(shard) {
-                let address = pool.address(shard, server);
-                let pool_state = pool.pool_state(shard, server);
-                let banned = pool.is_banned(address, Some(address.role));
-
-                res.put(data_row(&vec![
-                    address.name(),                         // name
-                    address.host.to_string(),               // host
-                    address.port.to_string(),               // port
-                    database_name.to_string(),              // database
-                    pool_config.user.username.to_string(),  // force_user
-                    pool_config.user.pool_size.to_string(), // pool_size
-                    "0".to_string(),                        // min_pool_size
-                    "0".to_string(),                        // reserve_pool
-                    pool_config.pool_mode.to_string(),      // pool_mode
-                    pool_config.user.pool_size.to_string(), // max_connections
-                    pool_state.connections.to_string(),     // current_connections
-                    "0".to_string(),                        // paused
-                    match banned {
-                        // disabled
-                        true => "1".to_string(),
-                        false => "0".to_string(),
-                    },
-                ]));
-            }
-        }
-    }
-    res.put(command_complete("SHOW"));
-
-    // ReadyForQuery
-    res.put_u8(b'Z');
-    res.put_i32(5);
-    res.put_u8(b'I');
-
-    write_all_half(stream, res).await
-}
-
-/// Ignore any SET commands the client sends.
-/// This is common initialization done by ORMs.
-async fn ignore_set<T>(stream: &mut T) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    custom_protocol_response_ok(stream, "SET").await
-}
-
-/// Reload the configuration file without restarting the process.
-async fn reload<T>(stream: &mut T, client_server_map: ClientServerMap) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    info!("Reloading config");
-
-    reload_config(client_server_map).await?;
-
-    get_config().show();
-
-    let mut res = BytesMut::new();
-
-    res.put(command_complete("RELOAD"));
-
-    // ReadyForQuery
-    res.put_u8(b'Z');
-    res.put_i32(5);
-    res.put_u8(b'I');
-
-    write_all_half(stream, res).await
-}
-
-/// Shows current configuration.
-async fn show_config<T>(stream: &mut T) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let config = &get_config();
-    let config: HashMap<String, String> = config.into();
-
-    // Configs that cannot be changed without restarting.
-    let immutables = ["host", "port", "connect_timeout"];
-
-    // Columns
-    let columns = vec![
-        ("key", DataType::Text),
-        ("value", DataType::Text),
-        ("default", DataType::Text),
-        ("changeable", DataType::Text),
-    ];
-
-    // Response data
-    let mut res = BytesMut::new();
-    res.put(row_description(&columns));
-
-    // DataRow rows
-    for (key, value) in config {
-        let changeable = if immutables.iter().filter(|col| *col == &key).count() == 1 {
-            "no".to_string()
-        } else {
-            "yes".to_string()
-        };
-
-        let row = vec![key, value, "-".to_string(), changeable];
-
-        res.put(data_row(&row));
-    }
-
-    res.put(command_complete("SHOW"));
-
-    // ReadyForQuery
-    res.put_u8(b'Z');
-    res.put_i32(5);
-    res.put_u8(b'I');
-
-    write_all_half(stream, res).await
-}
-
-/// Show shard and replicas statistics.
-async fn show_stats<T>(stream: &mut T) -> Result<(), Error>
-where
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let columns = vec![
-        ("database", DataType::Text),
-        ("user", DataType::Text),
-        ("total_xact_count", DataType::Numeric),
-        ("total_query_count", DataType::Numeric),
-        ("total_received", DataType::Numeric),
-        ("total_sent", DataType::Numeric),
-        ("total_xact_time", DataType::Numeric),
-        ("total_query_time", DataType::Numeric),
-        ("total_wait_time", DataType::Numeric),
-        ("avg_xact_count", DataType::Numeric),
-        ("avg_query_count", DataType::Numeric),
-        ("avg_recv", DataType::Numeric),
-        ("avg_sent", DataType::Numeric),
-        ("avg_xact_time", DataType::Numeric),
-        ("avg_query_time", DataType::Numeric),
-        ("avg_wait_time", DataType::Numeric),
-    ];
-
-    let stats = get_stats();
-    let mut res = BytesMut::new();
-    res.put(row_description(&columns));
-
-    for ((_db_name, username), pool) in get_all_pools() {
-        for shard in 0..pool.shards() {
-            for server in 0..pool.servers(shard) {
-                let address = pool.address(shard, server);
-                let stats = match stats.get(&address.id) {
-                    Some(stats) => stats.clone(),
-                    None => HashMap::new(),
-                };
-
-                let mut row = vec![address.name()];
-                row.push(username.clone());
-
-                for column in &columns[2..] {
-                    row.push(stats.get(column.0).unwrap_or(&0).to_string());
-                }
-
-                res.put(data_row(&row));
-            }
-        }
-    }
-
-    res.put(command_complete("SHOW"));
-
-    // ReadyForQuery
-    res.put_u8(b'Z');
-    res.put_i32(5);
-    res.put_u8(b'I');
-
-    write_all_half(stream, res).await
-}
diff --git a/rust_ref/src/client.rs b/rust_ref/src/client.rs
deleted file mode 100644
index 419448fb..00000000
--- a/rust_ref/src/client.rs
+++ /dev/null
@@ -1,1081 +0,0 @@
-/// Handle clients by pretending to be a PostgreSQL server.
-use bytes::{Buf, BufMut, BytesMut};
-use log::{debug, error, info, trace};
-use std::collections::HashMap;
-use tokio::io::{split, AsyncReadExt, BufReader, ReadHalf, WriteHalf};
-use tokio::net::TcpStream;
-use tokio::sync::broadcast::Receiver;
-use tokio::sync::mpsc::Sender;
-
-use crate::admin::{generate_server_info_for_admin, handle_admin};
-use crate::config::{get_config, Address};
-use crate::constants::*;
-use crate::errors::Error;
-use crate::messages::*;
-use crate::pool::{get_pool, ClientServerMap, ConnectionPool, PoolMode};
-use crate::query_router::{Command, QueryRouter};
-use crate::server::Server;
-use crate::stats::{get_reporter, Reporter};
-use crate::tls::Tls;
-
-use tokio_rustls::server::TlsStream;
-
-/// Type of connection received from client.
-enum ClientConnectionType {
-    Startup,
-    Tls,
-    CancelQuery,
-}
-
-/// The client state. One of these is created per client.
-pub struct Client<S, T> {
-    /// The reads are buffered (8K by default).
-    read: BufReader<S>,
-
-    /// We buffer the writes ourselves because we know the protocol
-    /// better than a stock buffer.
-    write: T,
-
-    /// Internal buffer, where we place messages until we have to flush
-    /// them to the backend.
-    buffer: BytesMut,
-
-    /// Address
-    addr: std::net::SocketAddr,
-
-    /// The client was started with the sole reason to cancel another running query.
-    cancel_mode: bool,
-
-    /// In transaction mode, the connection is released after each transaction.
-    /// Session mode has slightly higher throughput per client, but lower capacity.
-    transaction_mode: bool,
-
-    /// For query cancellation, the client is given a random process ID and secret on startup.
-    process_id: i32,
-    secret_key: i32,
-
-    /// Clients are mapped to servers while they use them. This allows a client
-    /// to connect and cancel a query.
-    client_server_map: ClientServerMap,
-
-    /// Client parameters, e.g. user, client_encoding, etc.
-    parameters: HashMap<String, String>,
-
-    /// Statistics
-    stats: Reporter,
-
-    /// Clients want to talk to admin database.
-    admin: bool,
-
-    /// Last address the client talked to.
-    last_address_id: Option<usize>,
-
-    /// Last server process id we talked to.
-    last_server_id: Option<i32>,
-
-    /// Connected to server
-    connected_to_server: bool,
-
-    /// Name of the server pool for this client (This comes from the database name in the connection string)
-    pool_name: String,
-
-    /// Postgres user for this client (This comes from the user in the connection string)
-    username: String,
-
-    /// Used to notify clients about an impending shutdown
-    shutdown: Receiver<()>,
-}
-
-/// Client entrypoint.
-pub async fn client_entrypoint(
-    mut stream: TcpStream,
-    client_server_map: ClientServerMap,
-    shutdown: Receiver<()>,
-    drain: Sender<i8>,
-    admin_only: bool,
-) -> Result<(), Error> {
-    // Figure out if the client wants TLS or not.
-    let addr = stream.peer_addr().unwrap();
-
-    match get_startup::<TcpStream>(&mut stream).await {
-        // Client requested a TLS connection.
-        Ok((ClientConnectionType::Tls, _)) => {
-            let config = get_config();
-
-            // TLS settings are configured, will setup TLS now.
-            if config.general.tls_certificate != None {
-                debug!("Accepting TLS request");
-
-                let mut yes = BytesMut::new();
-                yes.put_u8(b'S');
-                write_all(&mut stream, yes).await?;
-
-                // Negotiate TLS.
-                match startup_tls(stream, client_server_map, shutdown, admin_only).await {
-                    Ok(mut client) => {
-                        info!("Client {:?} connected (TLS)", addr);
-
-                        if !client.is_admin() {
-                            let _ = drain.send(1).await;
-                        }
-
-                        let result = client.handle().await;
-
-                        if !client.is_admin() {
-                            let _ = drain.send(-1).await;
-                        }
-
-                        result
-                    }
-                    Err(err) => Err(err),
-                }
-            }
-            // TLS is not configured, we cannot offer it.
-            else {
-                // Rejecting client request for TLS.
-                let mut no = BytesMut::new();
-                no.put_u8(b'N');
-                write_all(&mut stream, no).await?;
-
-                // Attempting regular startup. Client can disconnect now
-                // if they choose.
-                match get_startup::<TcpStream>(&mut stream).await {
-                    // Client accepted unencrypted connection.
-                    Ok((ClientConnectionType::Startup, bytes)) => {
-                        let (read, write) = split(stream);
-
-                        // Continue with regular startup.
-                        match Client::startup(
-                            read,
-                            write,
-                            addr,
-                            bytes,
-                            client_server_map,
-                            shutdown,
-                            admin_only,
-                        )
-                        .await
-                        {
-                            Ok(mut client) => {
-                                info!("Client {:?} connected (plain)", addr);
-
-                                if !client.is_admin() {
-                                    let _ = drain.send(1).await;
-                                }
-
-                                let result = client.handle().await;
-
-                                if !client.is_admin() {
-                                    let _ = drain.send(-1).await;
-                                }
-
-                                result
-                            }
-                            Err(err) => Err(err),
-                        }
-                    }
-
-                    // Client probably disconnected rejecting our plain text connection.
-                    _ => Err(Error::ProtocolSyncError),
-                }
-            }
-        }
-
-        // Client wants to use plain connection without encryption.
-        Ok((ClientConnectionType::Startup, bytes)) => {
-            let (read, write) = split(stream);
-
-            // Continue with regular startup.
-            match Client::startup(
-                read,
-                write,
-                addr,
-                bytes,
-                client_server_map,
-                shutdown,
-                admin_only,
-            )
-            .await
-            {
-                Ok(mut client) => {
-                    info!("Client {:?} connected (plain)", addr);
-
-                    if client.is_admin() {
-                        let _ = drain.send(1).await;
-                    }
-
-                    let result = client.handle().await;
-
-                    if !client.is_admin() {
-                        let _ = drain.send(-1).await;
-                    }
-
-                    result
-                }
-                Err(err) => Err(err),
-            }
-        }
-
-        // Client wants to cancel a query.
-        Ok((ClientConnectionType::CancelQuery, bytes)) => {
-            let (read, write) = split(stream);
-
-            // Continue with cancel query request.
-            match Client::cancel(read, write, addr, bytes, client_server_map, shutdown).await {
-                Ok(mut client) => {
-                    info!("Client {:?} issued a cancel query request", addr);
-
-                    if client.is_admin() {
-                        let _ = drain.send(1).await;
-                    }
-
-                    let result = client.handle().await;
-
-                    if !client.is_admin() {
-                        let _ = drain.send(-1).await;
-                    }
-
-                    result
-                }
-
-                Err(err) => Err(err),
-            }
-        }
-
-        // Something failed, probably the socket.
-        Err(err) => Err(err),
-    }
-}
-
-/// Handle the first message the client sends.
-async fn get_startup<S>(stream: &mut S) -> Result<(ClientConnectionType, BytesMut), Error>
-where
-    S: tokio::io::AsyncRead + std::marker::Unpin + tokio::io::AsyncWrite,
-{
-    // Get startup message length.
-    let len = match stream.read_i32().await {
-        Ok(len) => len,
-        Err(_) => return Err(Error::ClientBadStartup),
-    };
-
-    // Get the rest of the message.
-    let mut startup = vec![0u8; len as usize - 4];
-    match stream.read_exact(&mut startup).await {
-        Ok(_) => (),
-        Err(_) => return Err(Error::ClientBadStartup),
-    };
-
-    let mut bytes = BytesMut::from(&startup[..]);
-    let code = bytes.get_i32();
-
-    match code {
-        // Client is requesting SSL (TLS).
-        SSL_REQUEST_CODE => Ok((ClientConnectionType::Tls, bytes)),
-
-        // Client wants to use plain text, requesting regular startup.
-        PROTOCOL_VERSION_NUMBER => Ok((ClientConnectionType::Startup, bytes)),
-
-        // Client is requesting to cancel a running query (plain text connection).
-        CANCEL_REQUEST_CODE => Ok((ClientConnectionType::CancelQuery, bytes)),
-
-        // Something else, probably something is wrong and it's not our fault,
-        // e.g. badly implemented Postgres client.
-        _ => Err(Error::ProtocolSyncError),
-    }
-}
-
-/// Handle TLS connection negotiation.
-pub async fn startup_tls(
-    stream: TcpStream,
-    client_server_map: ClientServerMap,
-    shutdown: Receiver<()>,
-    admin_only: bool,
-) -> Result<Client<ReadHalf<TlsStream<TcpStream>>, WriteHalf<TlsStream<TcpStream>>>, Error> {
-    // Negotiate TLS.
-    let tls = Tls::new()?;
-    let addr = stream.peer_addr().unwrap();
-
-    let mut stream = match tls.acceptor.accept(stream).await {
-        Ok(stream) => stream,
-
-        // TLS negotiation failed.
-        Err(err) => {
-            error!("TLS negotiation failed: {:?}", err);
-            return Err(Error::TlsError);
-        }
-    };
-
-    // TLS negotiation successful.
-    // Continue with regular startup using encrypted connection.
-    match get_startup::<TlsStream<TcpStream>>(&mut stream).await {
-        // Got good startup message, proceeding like normal except we
-        // are encrypted now.
-        Ok((ClientConnectionType::Startup, bytes)) => {
-            let (read, write) = split(stream);
-
-            Client::startup(
-                read,
-                write,
-                addr,
-                bytes,
-                client_server_map,
-                shutdown,
-                admin_only,
-            )
-            .await
-        }
-
-        // Bad Postgres client.
-        _ => Err(Error::ProtocolSyncError),
-    }
-}
-
-impl<S, T> Client<S, T>
-where
-    S: tokio::io::AsyncRead + std::marker::Unpin,
-    T: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    pub fn is_admin(&self) -> bool {
-        self.admin
-    }
-
-    /// Handle Postgres client startup after TLS negotiation is complete
-    /// or over plain text.
-    pub async fn startup(
-        mut read: S,
-        mut write: T,
-        addr: std::net::SocketAddr,
-        bytes: BytesMut, // The rest of the startup message.
-        client_server_map: ClientServerMap,
-        shutdown: Receiver<()>,
-        admin_only: bool,
-    ) -> Result<Client<S, T>, Error> {
-        let config = get_config();
-        let stats = get_reporter();
-        let parameters = parse_startup(bytes.clone())?;
-
-        // These two parameters are mandatory by the protocol.
-        let pool_name = match parameters.get("database") {
-            Some(db) => db,
-            None => return Err(Error::ClientError),
-        };
-
-        let username = match parameters.get("user") {
-            Some(user) => user,
-            None => return Err(Error::ClientError),
-        };
-
-        let admin = ["pgcat", "pgbouncer"]
-            .iter()
-            .filter(|db| *db == &pool_name)
-            .count()
-            == 1;
-
-        // Kick any client that's not admin while we're in admin-only mode.
-        if !admin && admin_only {
-            debug!(
-                "Rejecting non-admin connection to {} when in admin only mode",
-                pool_name
-            );
-            error_response_terminal(
-                &mut write,
-                &format!("terminating connection due to administrator command"),
-            )
-            .await?;
-            return Err(Error::ShuttingDown);
-        }
-
-        // Generate random backend ID and secret key
-        let process_id: i32 = rand::random();
-        let secret_key: i32 = rand::random();
-
-        // Perform MD5 authentication.
-        // TODO: Add SASL support.
-        let salt = md5_challenge(&mut write).await?;
-
-        let code = match read.read_u8().await {
-            Ok(p) => p,
-            Err(_) => return Err(Error::SocketError),
-        };
-
-        // PasswordMessage
-        if code as char != 'p' {
-            debug!("Expected p, got {}", code as char);
-            return Err(Error::ProtocolSyncError);
-        }
-
-        let len = match read.read_i32().await {
-            Ok(len) => len,
-            Err(_) => return Err(Error::SocketError),
-        };
-
-        let mut password_response = vec![0u8; (len - 4) as usize];
-
-        match read.read_exact(&mut password_response).await {
-            Ok(_) => (),
-            Err(_) => return Err(Error::SocketError),
-        };
-
-        // Authenticate admin user.
-        let (transaction_mode, server_info) = if admin {
-            // Compare server and client hashes.
-            let password_hash = md5_hash_password(
-                &config.general.admin_username,
-                &config.general.admin_password,
-                &salt,
-            );
-
-            if password_hash != password_response {
-                debug!("Password authentication failed");
-                wrong_password(&mut write, username).await?;
-
-                return Err(Error::ClientError);
-            }
-
-            (false, generate_server_info_for_admin())
-        }
-        // Authenticate normal user.
-        else {
-            let pool = match get_pool(pool_name.clone(), username.clone()) {
-                Some(pool) => pool,
-                None => {
-                    error_response(
-                        &mut write,
-                        &format!(
-                            "No pool configured for database: {:?}, user: {:?}",
-                            pool_name, username
-                        ),
-                    )
-                    .await?;
-
-                    return Err(Error::ClientError);
-                }
-            };
-
-            // Compare server and client hashes.
-            let password_hash = md5_hash_password(&username, &pool.settings.user.password, &salt);
-
-            if password_hash != password_response {
-                debug!("Password authentication failed");
-                wrong_password(&mut write, username).await?;
-
-                return Err(Error::ClientError);
-            }
-
-            let transaction_mode = pool.settings.pool_mode == PoolMode::Transaction;
-
-            (transaction_mode, pool.server_info())
-        };
-
-        debug!("Password authentication successful");
-
-        auth_ok(&mut write).await?;
-        write_all(&mut write, server_info).await?;
-        backend_key_data(&mut write, process_id, secret_key).await?;
-        ready_for_query(&mut write).await?;
-
-        trace!("Startup OK");
-
-        return Ok(Client {
-            read: BufReader::new(read),
-            write: write,
-            addr,
-            buffer: BytesMut::with_capacity(8196),
-            cancel_mode: false,
-            transaction_mode,
-            process_id,
-            secret_key,
-            client_server_map,
-            parameters: parameters.clone(),
-            stats: stats,
-            admin: admin,
-            last_address_id: None,
-            last_server_id: None,
-            pool_name: pool_name.clone(),
-            username: username.clone(),
-            shutdown,
-            connected_to_server: false,
-        });
-    }
-
-    /// Handle cancel request.
-    pub async fn cancel(
-        read: S,
-        write: T,
-        addr: std::net::SocketAddr,
-        mut bytes: BytesMut, // The rest of the startup message.
-        client_server_map: ClientServerMap,
-        shutdown: Receiver<()>,
-    ) -> Result<Client<S, T>, Error> {
-        let process_id = bytes.get_i32();
-        let secret_key = bytes.get_i32();
-        return Ok(Client {
-            read: BufReader::new(read),
-            write: write,
-            addr,
-            buffer: BytesMut::with_capacity(8196),
-            cancel_mode: true,
-            transaction_mode: false,
-            process_id,
-            secret_key,
-            client_server_map,
-            parameters: HashMap::new(),
-            stats: get_reporter(),
-            admin: false,
-            last_address_id: None,
-            last_server_id: None,
-            pool_name: String::from("undefined"),
-            username: String::from("undefined"),
-            shutdown,
-            connected_to_server: false,
-        });
-    }
-
-    /// Handle a connected and authenticated client.
-    pub async fn handle(&mut self) -> Result<(), Error> {
-        // The client wants to cancel a query it has issued previously.
-        if self.cancel_mode {
-            trace!("Sending CancelRequest");
-
-            let (process_id, secret_key, address, port) = {
-                let guard = self.client_server_map.lock();
-
-                match guard.get(&(self.process_id, self.secret_key)) {
-                    // Drop the mutex as soon as possible.
-                    // We found the server the client is using for its query
-                    // that it wants to cancel.
-                    Some((process_id, secret_key, address, port)) => (
-                        process_id.clone(),
-                        secret_key.clone(),
-                        address.clone(),
-                        *port,
-                    ),
-
-                    // The client doesn't know / got the wrong server,
-                    // we're closing the connection for security reasons.
-                    None => return Ok(()),
-                }
-            };
-
-            // Opens a new separate connection to the server, sends the backend_id
-            // and secret_key and then closes it for security reasons. No other interactions
-            // take place.
-            return Ok(Server::cancel(&address, port, process_id, secret_key).await?);
-        }
-
-        // The query router determines where the query is going to go,
-        // e.g. primary, replica, which shard.
-        let mut query_router = QueryRouter::new();
-
-        // Our custom protocol loop.
-        // We expect the client to either start a transaction with regular queries
-        // or issue commands for our sharding and server selection protocol.
-        loop {
-            trace!(
-                "Client idle, waiting for message, transaction mode: {}",
-                self.transaction_mode
-            );
-
-            // Read a complete message from the client, which normally would be
-            // either a `Q` (query) or `P` (prepare, extended protocol).
-            // We can parse it here before grabbing a server from the pool,
-            // in case the client is sending some custom protocol messages, e.g.
-            // SET SHARDING KEY TO 'bigint';
-
-            let mut message = tokio::select! {
-                _ = self.shutdown.recv() => {
-                    if !self.admin {
-                        error_response_terminal(
-                            &mut self.write,
-                            &format!("terminating connection due to administrator command")
-                        ).await?;
-                        return Ok(())
-                    }
-
-                    // Admin clients ignore shutdown.
-                    else {
-                        read_message(&mut self.read).await?
-                    }
-                },
-                message_result = read_message(&mut self.read) => message_result?
-            };
-
-            // Avoid taking a server if the client just wants to disconnect.
-            if message[0] as char == 'X' {
-                debug!("Client disconnecting");
-                return Ok(());
-            }
-
-            // Handle admin database queries.
-            if self.admin {
-                debug!("Handling admin command");
-                handle_admin(&mut self.write, message, self.client_server_map.clone()).await?;
-                continue;
-            }
-
-            // Get a pool instance referenced by the most up-to-date
-            // pointer. This ensures we always read the latest config
-            // when starting a query.
-            let pool = match get_pool(self.pool_name.clone(), self.username.clone()) {
-                Some(pool) => pool,
-                None => {
-                    error_response(
-                        &mut self.write,
-                        &format!(
-                            "No pool configured for database: {:?}, user: {:?}",
-                            self.pool_name, self.username
-                        ),
-                    )
-                    .await?;
-                    return Err(Error::ClientError);
-                }
-            };
-            query_router.update_pool_settings(pool.settings.clone());
-            let current_shard = query_router.shard();
-
-            // Handle all custom protocol commands, if any.
-            match query_router.try_execute_command(message.clone()) {
-                // Normal query, not a custom command.
-                None => {
-                    if query_router.query_parser_enabled() {
-                        query_router.infer_role(message.clone());
-                    }
-                }
-
-                // SET SHARD TO
-                Some((Command::SetShard, _)) => {
-                    // Selected shard is not configured.
-                    if query_router.shard() >= pool.shards() {
-                        // Set the shard back to what it was.
-                        query_router.set_shard(current_shard);
-
-                        error_response(
-                            &mut self.write,
-                            &format!(
-                                "shard {} is more than configured {}, staying on shard {}",
-                                query_router.shard(),
-                                pool.shards(),
-                                current_shard,
-                            ),
-                        )
-                        .await?;
-                    } else {
-                        custom_protocol_response_ok(&mut self.write, "SET SHARD").await?;
-                    }
-                    continue;
-                }
-
-                // SET PRIMARY READS TO
-                Some((Command::SetPrimaryReads, _)) => {
-                    custom_protocol_response_ok(&mut self.write, "SET PRIMARY READS").await?;
-                    continue;
-                }
-
-                // SET SHARDING KEY TO
-                Some((Command::SetShardingKey, _)) => {
-                    custom_protocol_response_ok(&mut self.write, "SET SHARDING KEY").await?;
-                    continue;
-                }
-
-                // SET SERVER ROLE TO
-                Some((Command::SetServerRole, _)) => {
-                    custom_protocol_response_ok(&mut self.write, "SET SERVER ROLE").await?;
-                    continue;
-                }
-
-                // SHOW SERVER ROLE
-                Some((Command::ShowServerRole, value)) => {
-                    show_response(&mut self.write, "server role", &value).await?;
-                    continue;
-                }
-
-                // SHOW SHARD
-                Some((Command::ShowShard, value)) => {
-                    show_response(&mut self.write, "shard", &value).await?;
-                    continue;
-                }
-
-                // SHOW PRIMARY READS
-                Some((Command::ShowPrimaryReads, value)) => {
-                    show_response(&mut self.write, "primary reads", &value).await?;
-                    continue;
-                }
-            };
-
-            debug!("Waiting for connection from pool");
-
-            // Grab a server from the pool.
-            let connection = match pool
-                .get(query_router.shard(), query_router.role(), self.process_id)
-                .await
-            {
-                Ok(conn) => {
-                    debug!("Got connection from pool");
-                    conn
-                }
-                Err(err) => {
-                    // Clients do not expect to get SystemError followed by ReadyForQuery in the middle
-                    // of extended protocol submission. So we will hold off on sending the actual error
-                    // message to the client until we get 'S' message
-                    match message[0] as char {
-                        'P' | 'B' | 'E' | 'D' => (),
-                        _ => {
-                            error_response(
-                                &mut self.write,
-                                "could not get connection from the pool",
-                            )
-                            .await?;
-                        }
-                    };
-
-                    error!("Could not get connection from pool: {:?}", err);
-
-                    continue;
-                }
-            };
-
-            let mut reference = connection.0;
-            let address = connection.1;
-            let server = &mut *reference;
-
-            // Server is assigned to the client in case the client wants to
-            // cancel a query later.
-            server.claim(self.process_id, self.secret_key);
-            self.connected_to_server = true;
-
-            // Update statistics.
-            if let Some(last_address_id) = self.last_address_id {
-                self.stats
-                    .client_disconnecting(self.process_id, last_address_id);
-            }
-            self.stats.client_active(self.process_id, address.id);
-
-            self.last_address_id = Some(address.id);
-            self.last_server_id = Some(server.process_id());
-
-            debug!(
-                "Client {:?} talking to server {:?}",
-                self.addr,
-                server.address()
-            );
-
-            // Set application_name if any.
-            // TODO: investigate other parameters and set them too.
-            if self.parameters.contains_key("application_name") {
-                server
-                    .set_name(&self.parameters["application_name"])
-                    .await?;
-            }
-
-            // Transaction loop. Multiple queries can be issued by the client here.
-            // The connection belongs to the client until the transaction is over,
-            // or until the client disconnects if we are in session mode.
-            //
-            // If the client is in session mode, no more custom protocol
-            // commands will be accepted.
-            loop {
-                let mut message = if message.len() == 0 {
-                    trace!("Waiting for message inside transaction or in session mode");
-
-                    match read_message(&mut self.read).await {
-                        Ok(message) => message,
-                        Err(err) => {
-                            // Client disconnected inside a transaction.
-                            // Clean up the server and re-use it.
-                            // This prevents connection thrashing by bad clients.
-                            if server.in_transaction() {
-                                server.query("ROLLBACK").await?;
-                                server.query("DISCARD ALL").await?;
-                                server.set_name("pgcat").await?;
-                            }
-
-                            return Err(err);
-                        }
-                    }
-                } else {
-                    let msg = message.clone();
-                    message.clear();
-                    msg
-                };
-
-                // The message will be forwarded to the server intact. We still would like to
-                // parse it below to figure out what to do with it.
-                let original = message.clone();
-
-                let code = message.get_u8() as char;
-                let _len = message.get_i32() as usize;
-
-                trace!("Message: {}", code);
-
-                match code {
-                    // ReadyForQuery
-                    'Q' => {
-                        debug!("Sending query to server");
-
-                        self.send_and_receive_loop(code, original, server, &address, &pool)
-                            .await?;
-
-                        if !server.in_transaction() {
-                            // Report transaction executed statistics.
-                            self.stats.transaction(self.process_id, address.id);
-
-                            // Release server back to the pool if we are in transaction mode.
-                            // If we are in session mode, we keep the server until the client disconnects.
-                            if self.transaction_mode {
-                                break;
-                            }
-                        }
-                    }
-
-                    // Terminate
-                    'X' => {
-                        // Client closing. Rollback and clean up
-                        // connection before releasing into the pool.
-                        // Pgbouncer closes the connection which leads to
-                        // connection thrashing when clients misbehave.
-                        if server.in_transaction() {
-                            server.query("ROLLBACK").await?;
-                            server.query("DISCARD ALL").await?;
-                            server.set_name("pgcat").await?;
-                        }
-
-                        self.release();
-
-                        return Ok(());
-                    }
-
-                    // Parse
-                    // The query with placeholders is here, e.g. `SELECT * FROM users WHERE email = $1 AND active = $2`.
-                    'P' => {
-                        self.buffer.put(&original[..]);
-                    }
-
-                    // Bind
-                    // The placeholder's replacements are here, e.g. 'user@email.com' and 'true'
-                    'B' => {
-                        self.buffer.put(&original[..]);
-                    }
-
-                    // Describe
-                    // Command a client can issue to describe a previously prepared named statement.
-                    'D' => {
-                        self.buffer.put(&original[..]);
-                    }
-
-                    // Execute
-                    // Execute a prepared statement prepared in `P` and bound in `B`.
-                    'E' => {
-                        self.buffer.put(&original[..]);
-                    }
-
-                    // Sync
-                    // Frontend (client) is asking for the query result now.
-                    'S' => {
-                        debug!("Sending query to server");
-
-                        self.buffer.put(&original[..]);
-
-                        self.send_and_receive_loop(
-                            code,
-                            self.buffer.clone(),
-                            server,
-                            &address,
-                            &pool,
-                        )
-                        .await?;
-
-                        self.buffer.clear();
-
-                        if !server.in_transaction() {
-                            self.stats.transaction(self.process_id, address.id);
-
-                            // Release server back to the pool if we are in transaction mode.
-                            // If we are in session mode, we keep the server until the client disconnects.
-                            if self.transaction_mode {
-                                break;
-                            }
-                        }
-                    }
-
-                    // CopyData
-                    'd' => {
-                        // Forward the data to the server,
-                        // don't buffer it since it can be rather large.
-                        self.send_server_message(server, original, &address, &pool)
-                            .await?;
-                    }
-
-                    // CopyDone or CopyFail
-                    // Copy is done, successfully or not.
-                    'c' | 'f' => {
-                        self.send_server_message(server, original, &address, &pool)
-                            .await?;
-
-                        let response = self.receive_server_message(server, &address, &pool).await?;
-
-                        match write_all_half(&mut self.write, response).await {
-                            Ok(_) => (),
-                            Err(err) => {
-                                server.mark_bad();
-                                return Err(err);
-                            }
-                        };
-
-                        if !server.in_transaction() {
-                            self.stats.transaction(self.process_id, address.id);
-
-                            // Release server back to the pool if we are in transaction mode.
-                            // If we are in session mode, we keep the server until the client disconnects.
-                            if self.transaction_mode {
-                                break;
-                            }
-                        }
-                    }
-
-                    // Some unexpected message. We either did not implement the protocol correctly
-                    // or this is not a Postgres client we're talking to.
-                    _ => {
-                        error!("Unexpected code: {}", code);
-                    }
-                }
-            }
-
-            // The server is no longer bound to us, we can't cancel it's queries anymore.
-            debug!("Releasing server back into the pool");
-            self.stats.server_idle(server.process_id(), address.id);
-            self.connected_to_server = false;
-            self.release();
-            self.stats.client_idle(self.process_id, address.id);
-        }
-    }
-
-    /// Release the server from the client: it can't cancel its queries anymore.
-    pub fn release(&self) {
-        let mut guard = self.client_server_map.lock();
-        guard.remove(&(self.process_id, self.secret_key));
-    }
-
-    async fn send_and_receive_loop(
-        &mut self,
-        code: char,
-        message: BytesMut,
-        server: &mut Server,
-        address: &Address,
-        pool: &ConnectionPool,
-    ) -> Result<(), Error> {
-        debug!("Sending {} to server", code);
-
-        self.send_server_message(server, message, &address, &pool)
-            .await?;
-
-        // Read all data the server has to offer, which can be multiple messages
-        // buffered in 8196 bytes chunks.
-        loop {
-            let response = self.receive_server_message(server, &address, &pool).await?;
-
-            match write_all_half(&mut self.write, response).await {
-                Ok(_) => (),
-                Err(err) => {
-                    server.mark_bad();
-                    return Err(err);
-                }
-            };
-
-            if !server.is_data_available() {
-                break;
-            }
-        }
-
-        // Report query executed statistics.
-        self.stats.query(self.process_id, address.id);
-
-        Ok(())
-    }
-
-    async fn send_server_message(
-        &self,
-        server: &mut Server,
-        message: BytesMut,
-        address: &Address,
-        pool: &ConnectionPool,
-    ) -> Result<(), Error> {
-        match server.send(message).await {
-            Ok(_) => Ok(()),
-            Err(err) => {
-                pool.ban(address, self.process_id);
-                Err(err)
-            }
-        }
-    }
-
-    async fn receive_server_message(
-        &mut self,
-        server: &mut Server,
-        address: &Address,
-        pool: &ConnectionPool,
-    ) -> Result<BytesMut, Error> {
-        if pool.settings.user.statement_timeout > 0 {
-            match tokio::time::timeout(
-                tokio::time::Duration::from_millis(pool.settings.user.statement_timeout),
-                server.recv(),
-            )
-            .await
-            {
-                Ok(result) => match result {
-                    Ok(message) => Ok(message),
-                    Err(err) => {
-                        pool.ban(address, self.process_id);
-                        error_response_terminal(
-                            &mut self.write,
-                            &format!("error receiving data from server: {:?}", err),
-                        )
-                        .await?;
-                        Err(err)
-                    }
-                },
-                Err(_) => {
-                    error!(
-                        "Statement timeout while talking to {:?} with user {}",
-                        address, pool.settings.user.username
-                    );
-                    server.mark_bad();
-                    pool.ban(address, self.process_id);
-                    error_response_terminal(&mut self.write, "pool statement timeout").await?;
-                    Err(Error::StatementTimeout)
-                }
-            }
-        } else {
-            match server.recv().await {
-                Ok(message) => Ok(message),
-                Err(err) => {
-                    pool.ban(address, self.process_id);
-                    error_response_terminal(
-                        &mut self.write,
-                        &format!("error receiving data from server: {:?}", err),
-                    )
-                    .await?;
-                    Err(err)
-                }
-            }
-        }
-    }
-}
-
-impl<S, T> Drop for Client<S, T> {
-    fn drop(&mut self) {
-        let mut guard = self.client_server_map.lock();
-        guard.remove(&(self.process_id, self.secret_key));
-
-        // Dirty shutdown
-        // TODO: refactor, this is not the best way to handle state management.
-        if let Some(address_id) = self.last_address_id {
-            self.stats.client_disconnecting(self.process_id, address_id);
-
-            if self.connected_to_server {
-                if let Some(process_id) = self.last_server_id {
-                    self.stats.server_idle(process_id, address_id);
-                }
-            }
-        }
-    }
-}
diff --git a/rust_ref/src/config.rs b/rust_ref/src/config.rs
deleted file mode 100644
index 5c122611..00000000
--- a/rust_ref/src/config.rs
+++ /dev/null
@@ -1,672 +0,0 @@
-/// Parse the configuration file.
-use arc_swap::ArcSwap;
-use log::{error, info};
-use once_cell::sync::Lazy;
-use serde_derive::{Deserialize, Serialize};
-use std::collections::{HashMap, HashSet};
-use std::hash::Hash;
-use std::path::Path;
-use std::sync::Arc;
-use tokio::fs::File;
-use tokio::io::AsyncReadExt;
-use toml;
-
-use crate::errors::Error;
-use crate::tls::{load_certs, load_keys};
-use crate::{ClientServerMap, ConnectionPool};
-
-pub const VERSION: &str = env!("CARGO_PKG_VERSION");
-
-/// Globally available configuration.
-static CONFIG: Lazy<ArcSwap<Config>> = Lazy::new(|| ArcSwap::from_pointee(Config::default()));
-
-/// Server role: primary or replica.
-#[derive(Clone, PartialEq, Serialize, Deserialize, Hash, std::cmp::Eq, Debug, Copy)]
-pub enum Role {
-    Primary,
-    Replica,
-}
-
-impl ToString for Role {
-    fn to_string(&self) -> String {
-        match *self {
-            Role::Primary => "primary".to_string(),
-            Role::Replica => "replica".to_string(),
-        }
-    }
-}
-
-impl PartialEq<Option<Role>> for Role {
-    fn eq(&self, other: &Option<Role>) -> bool {
-        match other {
-            None => true,
-            Some(role) => *self == *role,
-        }
-    }
-}
-
-impl PartialEq<Role> for Option<Role> {
-    fn eq(&self, other: &Role) -> bool {
-        match *self {
-            None => true,
-            Some(role) => role == *other,
-        }
-    }
-}
-
-/// Address identifying a PostgreSQL server uniquely.
-#[derive(Clone, PartialEq, Hash, std::cmp::Eq, Debug)]
-pub struct Address {
-    /// Unique ID per addressable Postgres server.
-    pub id: usize,
-
-    /// Server host.
-    pub host: String,
-
-    /// Server port.
-    pub port: u16,
-
-    /// Shard number of this Postgres server.
-    pub shard: usize,
-
-    /// The name of the Postgres database.
-    pub database: String,
-
-    /// Server role: replica, primary.
-    pub role: Role,
-
-    /// If it's a replica, number it for reference and failover.
-    pub replica_number: usize,
-
-    /// Position of the server in the pool for failover.
-    pub address_index: usize,
-
-    /// The name of the user configured to use this pool.
-    pub username: String,
-
-    /// The name of this pool (i.e. database name visible to the client).
-    pub pool_name: String,
-}
-
-impl Default for Address {
-    fn default() -> Address {
-        Address {
-            id: 0,
-            host: String::from("127.0.0.1"),
-            port: 5432,
-            shard: 0,
-            address_index: 0,
-            replica_number: 0,
-            database: String::from("database"),
-            role: Role::Replica,
-            username: String::from("username"),
-            pool_name: String::from("pool_name"),
-        }
-    }
-}
-
-impl Address {
-    /// Address name (aka database) used in `SHOW STATS`, `SHOW DATABASES`, and `SHOW POOLS`.
-    pub fn name(&self) -> String {
-        match self.role {
-            Role::Primary => format!("{}_shard_{}_primary", self.pool_name, self.shard),
-
-            Role::Replica => format!(
-                "{}_shard_{}_replica_{}",
-                self.pool_name, self.shard, self.replica_number
-            ),
-        }
-    }
-}
-
-/// PostgreSQL user.
-#[derive(Clone, PartialEq, Hash, std::cmp::Eq, Serialize, Deserialize, Debug)]
-pub struct User {
-    pub username: String,
-    pub password: String,
-    pub pool_size: u32,
-    pub statement_timeout: u64,
-}
-
-impl Default for User {
-    fn default() -> User {
-        User {
-            username: String::from("postgres"),
-            password: String::new(),
-            pool_size: 15,
-            statement_timeout: 0,
-        }
-    }
-}
-
-/// General configuration.
-#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
-pub struct General {
-    pub host: String,
-    pub port: i16,
-    pub enable_prometheus_exporter: Option<bool>,
-    pub prometheus_exporter_port: i16,
-    pub connect_timeout: u64,
-    pub healthcheck_timeout: u64,
-    pub shutdown_timeout: u64,
-    pub healthcheck_delay: u64,
-    pub ban_time: i64,
-    pub autoreload: bool,
-    pub tls_certificate: Option<String>,
-    pub tls_private_key: Option<String>,
-    pub admin_username: String,
-    pub admin_password: String,
-}
-
-impl Default for General {
-    fn default() -> General {
-        General {
-            host: String::from("localhost"),
-            port: 5432,
-            enable_prometheus_exporter: Some(false),
-            prometheus_exporter_port: 9930,
-            connect_timeout: 5000,
-            healthcheck_timeout: 1000,
-            shutdown_timeout: 60000,
-            healthcheck_delay: 30000,
-            ban_time: 60,
-            autoreload: false,
-            tls_certificate: None,
-            tls_private_key: None,
-            admin_username: String::from("admin"),
-            admin_password: String::from("admin"),
-        }
-    }
-}
-#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
-pub struct Pool {
-    pub pool_mode: String,
-    pub default_role: String,
-    pub query_parser_enabled: bool,
-    pub primary_reads_enabled: bool,
-    pub sharding_function: String,
-    pub shards: HashMap<String, Shard>,
-    pub users: HashMap<String, User>,
-}
-impl Default for Pool {
-    fn default() -> Pool {
-        Pool {
-            pool_mode: String::from("transaction"),
-            shards: HashMap::from([(String::from("1"), Shard::default())]),
-            users: HashMap::default(),
-            default_role: String::from("any"),
-            query_parser_enabled: false,
-            primary_reads_enabled: true,
-            sharding_function: "pg_bigint_hash".to_string(),
-        }
-    }
-}
-
-/// Shard configuration.
-#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
-pub struct Shard {
-    pub database: String,
-    pub servers: Vec<(String, u16, String)>,
-}
-
-impl Default for Shard {
-    fn default() -> Shard {
-        Shard {
-            servers: vec![(String::from("localhost"), 5432, String::from("primary"))],
-            database: String::from("postgres"),
-        }
-    }
-}
-
-fn default_path() -> String {
-    String::from("pgcat.toml")
-}
-
-/// Configuration wrapper.
-#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
-pub struct Config {
-    // Serializer maintains the order of fields in the struct
-    // so we should always put simple fields before nested fields
-    // in all serializable structs to avoid ValueAfterTable errors
-    // These errors occur when the toml serializer is about to produce
-    // ambigous toml structure like the one below
-    // [main]
-    // field1_under_main = 1
-    // field2_under_main = 2
-    // [main.subconf]
-    // field1_under_subconf = 1
-    // field3_under_main = 3 # This field will be interpreted as being under subconf and not under main
-    #[serde(default = "default_path")]
-    pub path: String,
-
-    pub general: General,
-    pub pools: HashMap<String, Pool>,
-}
-
-impl Default for Config {
-    fn default() -> Config {
-        Config {
-            path: String::from("pgcat.toml"),
-            general: General::default(),
-            pools: HashMap::default(),
-        }
-    }
-}
-
-impl From<&Config> for std::collections::HashMap<String, String> {
-    fn from(config: &Config) -> HashMap<String, String> {
-        let mut r: Vec<(String, String)> = config
-            .pools
-            .iter()
-            .flat_map(|(pool_name, pool)| {
-                [
-                    (
-                        format!("pools.{}.pool_mode", pool_name),
-                        pool.pool_mode.clone(),
-                    ),
-                    (
-                        format!("pools.{}.primary_reads_enabled", pool_name),
-                        pool.primary_reads_enabled.to_string(),
-                    ),
-                    (
-                        format!("pools.{}.query_parser_enabled", pool_name),
-                        pool.query_parser_enabled.to_string(),
-                    ),
-                    (
-                        format!("pools.{}.default_role", pool_name),
-                        pool.default_role.clone(),
-                    ),
-                    (
-                        format!("pools.{}.sharding_function", pool_name),
-                        pool.sharding_function.clone(),
-                    ),
-                    (
-                        format!("pools.{:?}.shard_count", pool_name),
-                        pool.shards.len().to_string(),
-                    ),
-                    (
-                        format!("pools.{:?}.users", pool_name),
-                        pool.users
-                            .iter()
-                            .map(|(_username, user)| &user.username)
-                            .cloned()
-                            .collect::<Vec<String>>()
-                            .join(", "),
-                    ),
-                ]
-            })
-            .collect();
-
-        let mut static_settings = vec![
-            ("host".to_string(), config.general.host.to_string()),
-            ("port".to_string(), config.general.port.to_string()),
-            (
-                "prometheus_exporter_port".to_string(),
-                config.general.prometheus_exporter_port.to_string(),
-            ),
-            (
-                "connect_timeout".to_string(),
-                config.general.connect_timeout.to_string(),
-            ),
-            (
-                "healthcheck_timeout".to_string(),
-                config.general.healthcheck_timeout.to_string(),
-            ),
-            (
-                "shutdown_timeout".to_string(),
-                config.general.shutdown_timeout.to_string(),
-            ),
-            (
-                "healthcheck_delay".to_string(),
-                config.general.healthcheck_delay.to_string(),
-            ),
-            ("ban_time".to_string(), config.general.ban_time.to_string()),
-        ];
-
-        r.append(&mut static_settings);
-        return r.iter().cloned().collect();
-    }
-}
-
-impl Config {
-    /// Print current configuration.
-    pub fn show(&self) {
-        info!("Ban time: {}s", self.general.ban_time);
-        info!(
-            "Healthcheck timeout: {}ms",
-            self.general.healthcheck_timeout
-        );
-        info!("Connection timeout: {}ms", self.general.connect_timeout);
-        info!("Shutdown timeout: {}ms", self.general.shutdown_timeout);
-        info!("Healthcheck delay: {}ms", self.general.healthcheck_delay);
-        match self.general.tls_certificate.clone() {
-            Some(tls_certificate) => {
-                info!("TLS certificate: {}", tls_certificate);
-
-                match self.general.tls_private_key.clone() {
-                    Some(tls_private_key) => {
-                        info!("TLS private key: {}", tls_private_key);
-                        info!("TLS support is enabled");
-                    }
-
-                    None => (),
-                }
-            }
-
-            None => {
-                info!("TLS support is disabled");
-            }
-        };
-
-        for (pool_name, pool_config) in &self.pools {
-            // TODO: Make this output prettier (maybe a table?)
-            info!(
-                "[pool: {}] Maximum user connections: {}",
-                pool_name,
-                pool_config
-                    .users
-                    .iter()
-                    .map(|(_, user_cfg)| user_cfg.pool_size)
-                    .sum::<u32>()
-                    .to_string()
-            );
-            info!("[pool: {}] Pool mode: {}", pool_name, pool_config.pool_mode);
-            info!(
-                "[pool: {}] Sharding function: {}",
-                pool_name, pool_config.sharding_function
-            );
-            info!(
-                "[pool: {}] Primary reads: {}",
-                pool_name, pool_config.primary_reads_enabled
-            );
-            info!(
-                "[pool: {}] Query router: {}",
-                pool_name, pool_config.query_parser_enabled
-            );
-            info!(
-                "[pool: {}] Number of shards: {}",
-                pool_name,
-                pool_config.shards.len()
-            );
-            info!(
-                "[pool: {}] Number of users: {}",
-                pool_name,
-                pool_config.users.len()
-            );
-
-            for user in &pool_config.users {
-                info!(
-                    "[pool: {}][user: {}] Pool size: {}",
-                    pool_name, user.1.username, user.1.pool_size,
-                );
-                info!(
-                    "[pool: {}][user: {}] Statement timeout: {}",
-                    pool_name, user.1.username, user.1.statement_timeout
-                )
-            }
-        }
-    }
-}
-
-/// Get a read-only instance of the configuration
-/// from anywhere in the app.
-/// ArcSwap makes this cheap and quick.
-pub fn get_config() -> Config {
-    (*(*CONFIG.load())).clone()
-}
-
-/// Parse the configuration file located at the path.
-pub async fn parse(path: &str) -> Result<(), Error> {
-    let mut contents = String::new();
-    let mut file = match File::open(path).await {
-        Ok(file) => file,
-        Err(err) => {
-            error!("Could not open '{}': {}", path, err.to_string());
-            return Err(Error::BadConfig);
-        }
-    };
-
-    match file.read_to_string(&mut contents).await {
-        Ok(_) => (),
-        Err(err) => {
-            error!("Could not read config file: {}", err.to_string());
-            return Err(Error::BadConfig);
-        }
-    };
-
-    let mut config: Config = match toml::from_str(&contents) {
-        Ok(config) => config,
-        Err(err) => {
-            error!("Could not parse config file: {}", err.to_string());
-            return Err(Error::BadConfig);
-        }
-    };
-
-    // Validate TLS!
-    match config.general.tls_certificate.clone() {
-        Some(tls_certificate) => {
-            match load_certs(&Path::new(&tls_certificate)) {
-                Ok(_) => {
-                    // Cert is okay, but what about the private key?
-                    match config.general.tls_private_key.clone() {
-                        Some(tls_private_key) => match load_keys(&Path::new(&tls_private_key)) {
-                            Ok(_) => (),
-                            Err(err) => {
-                                error!("tls_private_key is incorrectly configured: {:?}", err);
-                                return Err(Error::BadConfig);
-                            }
-                        },
-
-                        None => {
-                            error!("tls_certificate is set, but the tls_private_key is not");
-                            return Err(Error::BadConfig);
-                        }
-                    };
-                }
-
-                Err(err) => {
-                    error!("tls_certificate is incorrectly configured: {:?}", err);
-                    return Err(Error::BadConfig);
-                }
-            }
-        }
-        None => (),
-    };
-
-    for (pool_name, pool) in &config.pools {
-        match pool.sharding_function.as_ref() {
-            "pg_bigint_hash" => (),
-            "sha1" => (),
-            _ => {
-                error!(
-                    "Supported sharding functions are: 'pg_bigint_hash', 'sha1', got: '{}' in pool {} settings",
-                    pool.sharding_function,
-                    pool_name
-                );
-                return Err(Error::BadConfig);
-            }
-        };
-
-        match pool.default_role.as_ref() {
-            "any" => (),
-            "primary" => (),
-            "replica" => (),
-            other => {
-                error!(
-                    "Query router default_role must be 'primary', 'replica', or 'any', got: '{}'",
-                    other
-                );
-                return Err(Error::BadConfig);
-            }
-        };
-
-        match pool.pool_mode.as_ref() {
-            "transaction" => (),
-            "session" => (),
-            other => {
-                error!(
-                    "pool_mode can be 'session' or 'transaction', got: '{}'",
-                    other
-                );
-                return Err(Error::BadConfig);
-            }
-        };
-
-        for shard in &pool.shards {
-            // We use addresses as unique identifiers,
-            // let's make sure they are unique in the config as well.
-            let mut dup_check = HashSet::new();
-            let mut primary_count = 0;
-
-            match shard.0.parse::<usize>() {
-                Ok(_) => (),
-                Err(_) => {
-                    error!(
-                        "Shard '{}' is not a valid number, shards must be numbered starting at 0",
-                        shard.0
-                    );
-                    return Err(Error::BadConfig);
-                }
-            };
-
-            if shard.1.servers.len() == 0 {
-                error!("Shard {} has no servers configured", shard.0);
-                return Err(Error::BadConfig);
-            }
-
-            for server in &shard.1.servers {
-                dup_check.insert(server);
-
-                // Check that we define only zero or one primary.
-                match server.2.as_ref() {
-                    "primary" => primary_count += 1,
-                    _ => (),
-                };
-
-                // Check role spelling.
-                match server.2.as_ref() {
-                    "primary" => (),
-                    "replica" => (),
-                    _ => {
-                        error!(
-                            "Shard {} server role must be either 'primary' or 'replica', got: '{}'",
-                            shard.0, server.2
-                        );
-                        return Err(Error::BadConfig);
-                    }
-                };
-            }
-
-            if primary_count > 1 {
-                error!("Shard {} has more than on primary configured", &shard.0);
-                return Err(Error::BadConfig);
-            }
-
-            if dup_check.len() != shard.1.servers.len() {
-                error!("Shard {} contains duplicate server configs", &shard.0);
-                return Err(Error::BadConfig);
-            }
-        }
-    }
-
-    config.path = path.to_string();
-
-    // Update the configuration globally.
-    CONFIG.store(Arc::new(config.clone()));
-
-    Ok(())
-}
-
-pub async fn reload_config(client_server_map: ClientServerMap) -> Result<bool, Error> {
-    let old_config = get_config();
-    match parse(&old_config.path).await {
-        Ok(()) => (),
-        Err(err) => {
-            error!("Config reload error: {:?}", err);
-            return Err(Error::BadConfig);
-        }
-    };
-    let new_config = get_config();
-
-    if old_config.pools != new_config.pools {
-        info!("Pool configuration changed, re-creating server pools");
-        ConnectionPool::from_config(client_server_map).await?;
-        Ok(true)
-    } else if old_config != new_config {
-        Ok(true)
-    } else {
-        Ok(false)
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[tokio::test]
-    async fn test_config() {
-        parse("pgcat.toml").await.unwrap();
-
-        assert_eq!(get_config().path, "pgcat.toml".to_string());
-
-        assert_eq!(get_config().general.ban_time, 60);
-        assert_eq!(get_config().pools.len(), 2);
-        assert_eq!(get_config().pools["sharded_db"].shards.len(), 3);
-        assert_eq!(get_config().pools["simple_db"].shards.len(), 1);
-        assert_eq!(get_config().pools["sharded_db"].users.len(), 2);
-        assert_eq!(get_config().pools["simple_db"].users.len(), 1);
-
-        assert_eq!(
-            get_config().pools["sharded_db"].shards["0"].servers[0].0,
-            "127.0.0.1"
-        );
-        assert_eq!(
-            get_config().pools["sharded_db"].shards["1"].servers[0].2,
-            "primary"
-        );
-        assert_eq!(
-            get_config().pools["sharded_db"].shards["1"].database,
-            "shard1"
-        );
-        assert_eq!(
-            get_config().pools["sharded_db"].users["0"].username,
-            "sharding_user"
-        );
-        assert_eq!(
-            get_config().pools["sharded_db"].users["1"].password,
-            "other_user"
-        );
-        assert_eq!(get_config().pools["sharded_db"].users["1"].pool_size, 21);
-        assert_eq!(get_config().pools["sharded_db"].default_role, "any");
-
-        assert_eq!(
-            get_config().pools["simple_db"].shards["0"].servers[0].0,
-            "127.0.0.1"
-        );
-        assert_eq!(
-            get_config().pools["simple_db"].shards["0"].servers[0].1,
-            5432
-        );
-        assert_eq!(
-            get_config().pools["simple_db"].shards["0"].database,
-            "some_db"
-        );
-        assert_eq!(get_config().pools["simple_db"].default_role, "primary");
-
-        assert_eq!(
-            get_config().pools["simple_db"].users["0"].username,
-            "simple_user"
-        );
-        assert_eq!(
-            get_config().pools["simple_db"].users["0"].password,
-            "simple_user"
-        );
-        assert_eq!(get_config().pools["simple_db"].users["0"].pool_size, 5);
-    }
-
-    #[tokio::test]
-    async fn test_serialize_configs() {
-        parse("pgcat.toml").await.unwrap();
-        print!("{}", toml::to_string(&get_config()).unwrap());
-    }
-}
diff --git a/rust_ref/src/constants.rs b/rust_ref/src/constants.rs
deleted file mode 100644
index 0900d7cc..00000000
--- a/rust_ref/src/constants.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-/// Various protocol constants, as defined in
-/// <https://www.postgresql.org/docs/12/protocol-message-formats.html>
-/// and elsewhere in the source code.
-
-// Used in the StartupMessage to indicate regular handshake.
-pub const PROTOCOL_VERSION_NUMBER: i32 = 196608;
-
-// SSLRequest: used to indicate we want an SSL connection.
-pub const SSL_REQUEST_CODE: i32 = 80877103;
-
-// CancelRequest: the cancel request code.
-pub const CANCEL_REQUEST_CODE: i32 = 80877102;
-
-// AuthenticationMD5Password
-pub const MD5_ENCRYPTED_PASSWORD: i32 = 5;
-
-// SASL
-pub const SASL: i32 = 10;
-pub const SASL_CONTINUE: i32 = 11;
-pub const SASL_FINAL: i32 = 12;
-pub const SCRAM_SHA_256: &str = "SCRAM-SHA-256";
-pub const NONCE_LENGTH: usize = 24;
-
-// AuthenticationOk
-pub const AUTHENTICATION_SUCCESSFUL: i32 = 0;
-
-// ErrorResponse: A code identifying the field type; if zero, this is the message terminator and no string follows.
-pub const MESSAGE_TERMINATOR: u8 = 0;
-
-//
-// Data types
-//
-pub const _OID_INT8: i32 = 20; // bigint
diff --git a/rust_ref/src/errors.rs b/rust_ref/src/errors.rs
deleted file mode 100644
index 50301f36..00000000
--- a/rust_ref/src/errors.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-/// Errors.
-
-/// Various errors.
-#[derive(Debug, PartialEq)]
-pub enum Error {
-    SocketError,
-    ClientBadStartup,
-    ProtocolSyncError,
-    ServerError,
-    BadConfig,
-    AllServersDown,
-    ClientError,
-    TlsError,
-    StatementTimeout,
-    ShuttingDown,
-}
diff --git a/rust_ref/src/main.rs b/rust_ref/src/main.rs
deleted file mode 100644
index a0c1d7cf..00000000
--- a/rust_ref/src/main.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright (c) 2022 Lev Kokotov <hi@levthe.dev>
-
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-extern crate arc_swap;
-extern crate async_trait;
-extern crate bb8;
-extern crate bytes;
-extern crate env_logger;
-extern crate exitcode;
-extern crate log;
-extern crate md5;
-extern crate num_cpus;
-extern crate once_cell;
-extern crate rustls_pemfile;
-extern crate serde;
-extern crate serde_derive;
-extern crate sqlparser;
-extern crate tokio;
-extern crate tokio_rustls;
-extern crate toml;
-
-use log::{debug, error, info};
-use parking_lot::Mutex;
-use tokio::net::TcpListener;
-use tokio::{
-    signal::unix::{signal as unix_signal, SignalKind},
-    sync::mpsc,
-};
-
-use std::collections::HashMap;
-use std::net::SocketAddr;
-use std::str::FromStr;
-use std::sync::Arc;
-use tokio::sync::broadcast;
-
-mod admin;
-mod client;
-mod config;
-mod constants;
-mod errors;
-mod messages;
-mod pool;
-mod prometheus;
-mod query_router;
-mod scram;
-mod server;
-mod sharding;
-mod stats;
-mod tls;
-
-use crate::config::{get_config, reload_config, VERSION};
-use crate::errors::Error;
-use crate::pool::{ClientServerMap, ConnectionPool};
-use crate::prometheus::start_metric_server;
-use crate::stats::{Collector, Reporter, REPORTER};
-
-#[tokio::main(worker_threads = 4)]
-async fn main() {
-    env_logger::init();
-    info!("Welcome to PgCat! Meow. (Version {})", VERSION);
-
-    if !query_router::QueryRouter::setup() {
-        error!("Could not setup query router");
-        std::process::exit(exitcode::CONFIG);
-    }
-
-    let args = std::env::args().collect::<Vec<String>>();
-
-    let config_file = if args.len() == 2 {
-        args[1].to_string()
-    } else {
-        String::from("pgcat.toml")
-    };
-
-    match config::parse(&config_file).await {
-        Ok(_) => (),
-        Err(err) => {
-            error!("Config parse error: {:?}", err);
-            std::process::exit(exitcode::CONFIG);
-        }
-    };
-
-    let config = get_config();
-
-    if let Some(true) = config.general.enable_prometheus_exporter {
-        let http_addr_str = format!(
-            "{}:{}",
-            config.general.host, config.general.prometheus_exporter_port
-        );
-        let http_addr = match SocketAddr::from_str(&http_addr_str) {
-            Ok(addr) => addr,
-            Err(err) => {
-                error!("Invalid http address: {}", err);
-                std::process::exit(exitcode::CONFIG);
-            }
-        };
-        tokio::task::spawn(async move {
-            start_metric_server(http_addr).await;
-        });
-    }
-
-    let addr = format!("{}:{}", config.general.host, config.general.port);
-
-    let listener = match TcpListener::bind(&addr).await {
-        Ok(sock) => sock,
-        Err(err) => {
-            error!("Listener socket error: {:?}", err);
-            std::process::exit(exitcode::CONFIG);
-        }
-    };
-
-    info!("Running on {}", addr);
-
-    config.show();
-
-    // Tracks which client is connected to which server for query cancellation.
-    let client_server_map: ClientServerMap = Arc::new(Mutex::new(HashMap::new()));
-
-    // Statistics reporting.
-    let (stats_tx, stats_rx) = mpsc::channel(100_000);
-    REPORTER.store(Arc::new(Reporter::new(stats_tx.clone())));
-
-    // Connection pool that allows to query all shards and replicas.
-    match ConnectionPool::from_config(client_server_map.clone()).await {
-        Ok(_) => (),
-        Err(err) => {
-            error!("Pool error: {:?}", err);
-            std::process::exit(exitcode::CONFIG);
-        }
-    };
-
-    tokio::task::spawn(async move {
-        let mut stats_collector = Collector::new(stats_rx, stats_tx.clone());
-        stats_collector.collect().await;
-    });
-
-    info!("Config autoreloader: {}", config.general.autoreload);
-
-    let mut autoreload_interval = tokio::time::interval(tokio::time::Duration::from_millis(15_000));
-    let autoreload_client_server_map = client_server_map.clone();
-    tokio::task::spawn(async move {
-        loop {
-            autoreload_interval.tick().await;
-            if config.general.autoreload {
-                info!("Automatically reloading config");
-
-                match reload_config(autoreload_client_server_map.clone()).await {
-                    Ok(changed) => {
-                        if changed {
-                            get_config().show()
-                        }
-                    }
-                    Err(_) => (),
-                };
-            }
-        }
-    });
-
-    let mut term_signal = unix_signal(SignalKind::terminate()).unwrap();
-    let mut interrupt_signal = unix_signal(SignalKind::interrupt()).unwrap();
-    let mut sighup_signal = unix_signal(SignalKind::hangup()).unwrap();
-    let (shutdown_tx, _) = broadcast::channel::<()>(1);
-    let (drain_tx, mut drain_rx) = mpsc::channel::<i8>(2048);
-    let (exit_tx, mut exit_rx) = mpsc::channel::<()>(1);
-
-    info!("Waiting for clients");
-
-    let mut admin_only = false;
-    let mut total_clients = 0;
-
-    loop {
-        tokio::select! {
-            // Reload config:
-            // kill -SIGHUP $(pgrep pgcat)
-            _ = sighup_signal.recv() => {
-                info!("Reloading config");
-
-                match reload_config(client_server_map.clone()).await {
-                    Ok(_) => (),
-                    Err(_) => (),
-                };
-
-                get_config().show();
-            },
-
-            // Initiate graceful shutdown sequence on sig int
-            _ = interrupt_signal.recv() => {
-                info!("Got SIGINT, waiting for client connection drain now");
-                admin_only = true;
-
-                // Broadcast that client tasks need to finish
-                let _ = shutdown_tx.send(());
-                let exit_tx = exit_tx.clone();
-                let _ = drain_tx.send(0).await;
-
-                tokio::task::spawn(async move {
-                    let mut interval = tokio::time::interval(tokio::time::Duration::from_millis(config.general.shutdown_timeout));
-
-                    // First tick fires immediately.
-                    interval.tick().await;
-
-                    // Second one in the interval time.
-                    interval.tick().await;
-
-                    // We're done waiting.
-                    error!("Timed out waiting for clients");
-
-                    let _ = exit_tx.send(()).await;
-                });
-            },
-
-            _ = term_signal.recv() => break,
-
-            new_client = listener.accept() => {
-                let (socket, addr) = match new_client {
-                    Ok((socket, addr)) => (socket, addr),
-                    Err(err) => {
-                        error!("{:?}", err);
-                        continue;
-                    }
-                };
-
-                let shutdown_rx = shutdown_tx.subscribe();
-                let drain_tx = drain_tx.clone();
-                let client_server_map = client_server_map.clone();
-
-                tokio::task::spawn(async move {
-                    let start = chrono::offset::Utc::now().naive_utc();
-
-                    match client::client_entrypoint(
-                        socket,
-                        client_server_map,
-                        shutdown_rx,
-                        drain_tx,
-                        admin_only,
-                    )
-                    .await
-                    {
-                        Ok(()) => {
-
-                            let duration = chrono::offset::Utc::now().naive_utc() - start;
-
-                            info!(
-                                "Client {:?} disconnected, session duration: {}",
-                                addr,
-                                format_duration(&duration)
-                            );
-                        }
-
-                        Err(err) => {
-                            match err {
-                                // Don't count the clients we rejected.
-                                Error::ShuttingDown => (),
-                                _ => {
-                                    // drain_tx.send(-1).await.unwrap();
-                                }
-                            }
-
-                            debug!("Client disconnected with error {:?}", err);
-                        }
-                    };
-                });
-            }
-
-            _ = exit_rx.recv() => {
-                break;
-            }
-
-            client_ping = drain_rx.recv() => {
-                let client_ping = client_ping.unwrap();
-                total_clients += client_ping;
-
-                if total_clients == 0 && admin_only {
-                    let _ = exit_tx.send(()).await;
-                }
-            }
-        }
-    }
-
-    info!("Shutting down...");
-}
-
-/// Format chrono::Duration to be more human-friendly.
-///
-/// # Arguments
-///
-/// * `duration` - A duration of time
-fn format_duration(duration: &chrono::Duration) -> String {
-    let seconds = {
-        let seconds = duration.num_seconds() % 60;
-        if seconds < 10 {
-            format!("0{}", seconds)
-        } else {
-            format!("{}", seconds)
-        }
-    };
-
-    let minutes = {
-        let minutes = duration.num_minutes() % 60;
-        if minutes < 10 {
-            format!("0{}", minutes)
-        } else {
-            format!("{}", minutes)
-        }
-    };
-
-    let hours = {
-        let hours = duration.num_hours() % 24;
-        if hours < 10 {
-            format!("0{}", hours)
-        } else {
-            format!("{}", hours)
-        }
-    };
-
-    let days = duration.num_days().to_string();
-
-    format!("{}d {}:{}:{}", days, hours, minutes, seconds)
-}
diff --git a/rust_ref/src/messages.rs b/rust_ref/src/messages.rs
deleted file mode 100644
index 113e1ed5..00000000
--- a/rust_ref/src/messages.rs
+++ /dev/null
@@ -1,514 +0,0 @@
-/// Helper functions to send one-off protocol messages
-/// and handle TcpStream (TCP socket).
-use bytes::{Buf, BufMut, BytesMut};
-use md5::{Digest, Md5};
-use tokio::io::{AsyncReadExt, AsyncWriteExt};
-use tokio::net::TcpStream;
-
-use crate::errors::Error;
-use std::collections::HashMap;
-use std::mem;
-
-/// Postgres data type mappings
-/// used in RowDescription ('T') message.
-pub enum DataType {
-    Text,
-    Int4,
-    Numeric,
-}
-
-impl From<&DataType> for i32 {
-    fn from(data_type: &DataType) -> i32 {
-        match data_type {
-            DataType::Text => 25,
-            DataType::Int4 => 23,
-            DataType::Numeric => 1700,
-        }
-    }
-}
-
-/// Tell the client that authentication handshake completed successfully.
-pub async fn auth_ok<S>(stream: &mut S) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let mut auth_ok = BytesMut::with_capacity(9);
-
-    auth_ok.put_u8(b'R');
-    auth_ok.put_i32(8);
-    auth_ok.put_i32(0);
-
-    Ok(write_all(stream, auth_ok).await?)
-}
-
-/// Generate md5 password challenge.
-pub async fn md5_challenge<S>(stream: &mut S) -> Result<[u8; 4], Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    // let mut rng = rand::thread_rng();
-    let salt: [u8; 4] = [
-        rand::random(),
-        rand::random(),
-        rand::random(),
-        rand::random(),
-    ];
-
-    let mut res = BytesMut::new();
-    res.put_u8(b'R');
-    res.put_i32(12);
-    res.put_i32(5); // MD5
-    res.put_slice(&salt[..]);
-
-    write_all(stream, res).await?;
-    Ok(salt)
-}
-
-/// Give the client the process_id and secret we generated
-/// used in query cancellation.
-pub async fn backend_key_data<S>(
-    stream: &mut S,
-    backend_id: i32,
-    secret_key: i32,
-) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let mut key_data = BytesMut::from(&b"K"[..]);
-    key_data.put_i32(12);
-    key_data.put_i32(backend_id);
-    key_data.put_i32(secret_key);
-
-    Ok(write_all(stream, key_data).await?)
-}
-
-/// Construct a `Q`: Query message.
-pub fn simple_query(query: &str) -> BytesMut {
-    let mut res = BytesMut::from(&b"Q"[..]);
-    let query = format!("{}\0", query);
-
-    res.put_i32(query.len() as i32 + 4);
-    res.put_slice(&query.as_bytes());
-
-    res
-}
-
-/// Tell the client we're ready for another query.
-pub async fn ready_for_query<S>(stream: &mut S) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let mut bytes = BytesMut::with_capacity(
-        mem::size_of::<u8>() + mem::size_of::<i32>() + mem::size_of::<u8>(),
-    );
-
-    bytes.put_u8(b'Z');
-    bytes.put_i32(5);
-    bytes.put_u8(b'I'); // Idle
-
-    Ok(write_all(stream, bytes).await?)
-}
-
-/// Send the startup packet the server. We're pretending we're a Pg client.
-/// This tells the server which user we are and what database we want.
-pub async fn startup(stream: &mut TcpStream, user: &str, database: &str) -> Result<(), Error> {
-    let mut bytes = BytesMut::with_capacity(25);
-
-    bytes.put_i32(196608); // Protocol number
-
-    // User
-    bytes.put(&b"user\0"[..]);
-    bytes.put_slice(&user.as_bytes());
-    bytes.put_u8(0);
-
-    // Database
-    bytes.put(&b"database\0"[..]);
-    bytes.put_slice(&database.as_bytes());
-    bytes.put_u8(0);
-    bytes.put_u8(0); // Null terminator
-
-    let len = bytes.len() as i32 + 4i32;
-
-    let mut startup = BytesMut::with_capacity(len as usize);
-
-    startup.put_i32(len);
-    startup.put(bytes);
-
-    match stream.write_all(&startup).await {
-        Ok(_) => Ok(()),
-        Err(_) => return Err(Error::SocketError),
-    }
-}
-
-/// Parse the params the server sends as a key/value format.
-pub fn parse_params(mut bytes: BytesMut) -> Result<HashMap<String, String>, Error> {
-    let mut result = HashMap::new();
-    let mut buf = Vec::new();
-    let mut tmp = String::new();
-
-    while bytes.has_remaining() {
-        let mut c = bytes.get_u8();
-
-        // Null-terminated C-strings.
-        while c != 0 {
-            tmp.push(c as char);
-            c = bytes.get_u8();
-        }
-
-        if tmp.len() > 0 {
-            buf.push(tmp.clone());
-            tmp.clear();
-        }
-    }
-
-    // Expect pairs of name and value
-    // and at least one pair to be present.
-    if buf.len() % 2 != 0 || buf.len() < 2 {
-        return Err(Error::ClientBadStartup);
-    }
-
-    let mut i = 0;
-    while i < buf.len() {
-        let name = buf[i].clone();
-        let value = buf[i + 1].clone();
-        let _ = result.insert(name, value);
-        i += 2;
-    }
-
-    Ok(result)
-}
-
-/// Parse StartupMessage parameters.
-/// e.g. user, database, application_name, etc.
-pub fn parse_startup(bytes: BytesMut) -> Result<HashMap<String, String>, Error> {
-    let result = parse_params(bytes)?;
-
-    // Minimum required parameters
-    // I want to have the user at the very minimum, according to the protocol spec.
-    if !result.contains_key("user") {
-        return Err(Error::ClientBadStartup);
-    }
-
-    Ok(result)
-}
-
-/// Create md5 password hash given a salt.
-pub fn md5_hash_password(user: &str, password: &str, salt: &[u8]) -> Vec<u8> {
-    let mut md5 = Md5::new();
-
-    // First pass
-    md5.update(&password.as_bytes());
-    md5.update(&user.as_bytes());
-
-    let output = md5.finalize_reset();
-
-    // Second pass
-    md5.update(format!("{:x}", output));
-    md5.update(salt);
-
-    let mut password = format!("md5{:x}", md5.finalize())
-        .chars()
-        .map(|x| x as u8)
-        .collect::<Vec<u8>>();
-    password.push(0);
-
-    password
-}
-
-/// Send password challenge response to the server.
-/// This is the MD5 challenge.
-pub async fn md5_password<S>(
-    stream: &mut S,
-    user: &str,
-    password: &str,
-    salt: &[u8],
-) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let password = md5_hash_password(user, password, salt);
-
-    let mut message = BytesMut::with_capacity(password.len() as usize + 5);
-
-    message.put_u8(b'p');
-    message.put_i32(password.len() as i32 + 4);
-    message.put_slice(&password[..]);
-
-    Ok(write_all(stream, message).await?)
-}
-
-/// Implements a response to our custom `SET SHARDING KEY`
-/// and `SET SERVER ROLE` commands.
-/// This tells the client we're ready for the next query.
-pub async fn custom_protocol_response_ok<S>(stream: &mut S, message: &str) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let mut res = BytesMut::with_capacity(25);
-
-    let set_complete = BytesMut::from(&format!("{}\0", message)[..]);
-    let len = (set_complete.len() + 4) as i32;
-
-    // CommandComplete
-    res.put_u8(b'C');
-    res.put_i32(len);
-    res.put_slice(&set_complete[..]);
-
-    write_all_half(stream, res).await?;
-    ready_for_query(stream).await
-}
-
-/// Send a custom error message to the client.
-/// Tell the client we are ready for the next query and no rollback is necessary.
-/// Docs on error codes: <https://www.postgresql.org/docs/12/errcodes-appendix.html>.
-pub async fn error_response<S>(stream: &mut S, message: &str) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    error_response_terminal(stream, message).await?;
-    ready_for_query(stream).await
-}
-
-/// Send a custom error message to the client.
-/// Tell the client we are ready for the next query and no rollback is necessary.
-/// Docs on error codes: <https://www.postgresql.org/docs/12/errcodes-appendix.html>.
-pub async fn error_response_terminal<S>(stream: &mut S, message: &str) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let mut error = BytesMut::new();
-
-    // Error level
-    error.put_u8(b'S');
-    error.put_slice(&b"FATAL\0"[..]);
-
-    // Error level (non-translatable)
-    error.put_u8(b'V');
-    error.put_slice(&b"FATAL\0"[..]);
-
-    // Error code: not sure how much this matters.
-    error.put_u8(b'C');
-    error.put_slice(&b"58000\0"[..]); // system_error, see Appendix A.
-
-    // The short error message.
-    error.put_u8(b'M');
-    error.put_slice(&format!("{}\0", message).as_bytes());
-
-    // No more fields follow.
-    error.put_u8(0);
-
-    // Compose the two message reply.
-    let mut res = BytesMut::with_capacity(error.len() + 5);
-
-    res.put_u8(b'E');
-    res.put_i32(error.len() as i32 + 4);
-    res.put(error);
-
-    Ok(write_all_half(stream, res).await?)
-}
-
-pub async fn wrong_password<S>(stream: &mut S, user: &str) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    let mut error = BytesMut::new();
-
-    // Error level
-    error.put_u8(b'S');
-    error.put_slice(&b"FATAL\0"[..]);
-
-    // Error level (non-translatable)
-    error.put_u8(b'V');
-    error.put_slice(&b"FATAL\0"[..]);
-
-    // Error code: not sure how much this matters.
-    error.put_u8(b'C');
-    error.put_slice(&b"28P01\0"[..]); // system_error, see Appendix A.
-
-    // The short error message.
-    error.put_u8(b'M');
-    error.put_slice(&format!("password authentication failed for user \"{}\"\0", user).as_bytes());
-
-    // No more fields follow.
-    error.put_u8(0);
-
-    // Compose the two message reply.
-    let mut res = BytesMut::new();
-
-    res.put_u8(b'E');
-    res.put_i32(error.len() as i32 + 4);
-
-    res.put(error);
-
-    write_all(stream, res).await
-}
-
-/// Respond to a SHOW SHARD command.
-pub async fn show_response<S>(stream: &mut S, name: &str, value: &str) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    // A SELECT response consists of:
-    // 1. RowDescription
-    // 2. One or more DataRow
-    // 3. CommandComplete
-    // 4. ReadyForQuery
-
-    // The final messages sent to the client
-    let mut res = BytesMut::new();
-
-    // RowDescription
-    res.put(row_description(&vec![(name, DataType::Text)]));
-
-    // DataRow
-    res.put(data_row(&vec![value.to_string()]));
-
-    // CommandComplete
-    res.put(command_complete("SELECT 1"));
-
-    write_all_half(stream, res).await?;
-    ready_for_query(stream).await
-}
-
-pub fn row_description(columns: &Vec<(&str, DataType)>) -> BytesMut {
-    let mut res = BytesMut::new();
-    let mut row_desc = BytesMut::new();
-
-    // how many colums we are storing
-    row_desc.put_i16(columns.len() as i16);
-
-    for (name, data_type) in columns {
-        // Column name
-        row_desc.put_slice(&format!("{}\0", name).as_bytes());
-
-        // Doesn't belong to any table
-        row_desc.put_i32(0);
-
-        // Doesn't belong to any table
-        row_desc.put_i16(0);
-
-        // Text
-        row_desc.put_i32(data_type.into());
-
-        // Text size = variable (-1)
-        let type_size = match data_type {
-            DataType::Text => -1,
-            DataType::Int4 => 4,
-            DataType::Numeric => -1,
-        };
-
-        row_desc.put_i16(type_size);
-
-        // Type modifier: none that I know
-        row_desc.put_i32(-1);
-
-        // Format being used: text (0), binary (1)
-        row_desc.put_i16(0);
-    }
-
-    res.put_u8(b'T');
-    res.put_i32(row_desc.len() as i32 + 4);
-    res.put(row_desc);
-
-    res
-}
-
-/// Create a DataRow message.
-pub fn data_row(row: &Vec<String>) -> BytesMut {
-    let mut res = BytesMut::new();
-    let mut data_row = BytesMut::new();
-
-    data_row.put_i16(row.len() as i16);
-
-    for column in row {
-        let column = column.as_bytes();
-        data_row.put_i32(column.len() as i32);
-        data_row.put_slice(&column);
-    }
-
-    res.put_u8(b'D');
-    res.put_i32(data_row.len() as i32 + 4);
-    res.put(data_row);
-
-    res
-}
-
-/// Create a CommandComplete message.
-pub fn command_complete(command: &str) -> BytesMut {
-    let cmd = BytesMut::from(format!("{}\0", command).as_bytes());
-    let mut res = BytesMut::new();
-    res.put_u8(b'C');
-    res.put_i32(cmd.len() as i32 + 4);
-    res.put(cmd);
-    res
-}
-
-/// Write all data in the buffer to the TcpStream.
-pub async fn write_all<S>(stream: &mut S, buf: BytesMut) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    match stream.write_all(&buf).await {
-        Ok(_) => Ok(()),
-        Err(_) => return Err(Error::SocketError),
-    }
-}
-
-/// Write all the data in the buffer to the TcpStream, write owned half (see mpsc).
-pub async fn write_all_half<S>(stream: &mut S, buf: BytesMut) -> Result<(), Error>
-where
-    S: tokio::io::AsyncWrite + std::marker::Unpin,
-{
-    match stream.write_all(&buf).await {
-        Ok(_) => Ok(()),
-        Err(_) => return Err(Error::SocketError),
-    }
-}
-
-/// Read a complete message from the socket.
-pub async fn read_message<S>(stream: &mut S) -> Result<BytesMut, Error>
-where
-    S: tokio::io::AsyncRead + std::marker::Unpin,
-{
-    let code = match stream.read_u8().await {
-        Ok(code) => code,
-        Err(_) => return Err(Error::SocketError),
-    };
-
-    let len = match stream.read_i32().await {
-        Ok(len) => len,
-        Err(_) => return Err(Error::SocketError),
-    };
-
-    let mut buf = vec![0u8; len as usize - 4];
-
-    match stream.read_exact(&mut buf).await {
-        Ok(_) => (),
-        Err(_) => return Err(Error::SocketError),
-    };
-
-    let mut bytes = BytesMut::with_capacity(len as usize + 1);
-
-    bytes.put_u8(code);
-    bytes.put_i32(len);
-    bytes.put_slice(&buf);
-
-    Ok(bytes)
-}
-
-pub fn server_paramater_message(key: &str, value: &str) -> BytesMut {
-    let mut server_info = BytesMut::new();
-
-    let null_byte_size = 1;
-    let len: usize =
-        mem::size_of::<i32>() + key.len() + null_byte_size + value.len() + null_byte_size;
-
-    server_info.put_slice("S".as_bytes());
-    server_info.put_i32(len.try_into().unwrap());
-    server_info.put_slice(key.as_bytes());
-    server_info.put_bytes(0, 1);
-    server_info.put_slice(value.as_bytes());
-    server_info.put_bytes(0, 1);
-
-    return server_info;
-}
diff --git a/rust_ref/src/pool.rs b/rust_ref/src/pool.rs
deleted file mode 100644
index 99cccaf1..00000000
--- a/rust_ref/src/pool.rs
+++ /dev/null
@@ -1,626 +0,0 @@
-use arc_swap::ArcSwap;
-use async_trait::async_trait;
-use bb8::{ManageConnection, Pool, PooledConnection};
-use bytes::BytesMut;
-use chrono::naive::NaiveDateTime;
-use log::{debug, error, info, warn};
-use once_cell::sync::Lazy;
-use parking_lot::{Mutex, RwLock};
-use rand::seq::SliceRandom;
-use rand::thread_rng;
-use std::collections::HashMap;
-use std::sync::Arc;
-use std::time::Instant;
-
-use crate::config::{get_config, Address, Role, User};
-use crate::errors::Error;
-
-use crate::server::Server;
-use crate::sharding::ShardingFunction;
-use crate::stats::{get_reporter, Reporter};
-
-pub type BanList = Arc<RwLock<Vec<HashMap<Address, NaiveDateTime>>>>;
-pub type ClientServerMap = Arc<Mutex<HashMap<(i32, i32), (i32, i32, String, u16)>>>;
-pub type PoolMap = HashMap<(String, String), ConnectionPool>;
-/// The connection pool, globally available.
-/// This is atomic and safe and read-optimized.
-/// The pool is recreated dynamically when the config is reloaded.
-pub static POOLS: Lazy<ArcSwap<PoolMap>> = Lazy::new(|| ArcSwap::from_pointee(HashMap::default()));
-
-/// Pool mode:
-/// - transaction: server serves one transaction,
-/// - session: server is attached to the client.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum PoolMode {
-    Session,
-    Transaction,
-}
-
-impl std::fmt::Display for PoolMode {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        match *self {
-            PoolMode::Session => write!(f, "session"),
-            PoolMode::Transaction => write!(f, "transaction"),
-        }
-    }
-}
-
-/// Pool settings.
-#[derive(Clone, Debug)]
-pub struct PoolSettings {
-    /// Transaction or Session.
-    pub pool_mode: PoolMode,
-
-    // Number of shards.
-    pub shards: usize,
-
-    // Connecting user.
-    pub user: User,
-
-    // Default server role to connect to.
-    pub default_role: Option<Role>,
-
-    // Enable/disable query parser.
-    pub query_parser_enabled: bool,
-
-    // Read from the primary as well or not.
-    pub primary_reads_enabled: bool,
-
-    // Sharding function.
-    pub sharding_function: ShardingFunction,
-}
-
-impl Default for PoolSettings {
-    fn default() -> PoolSettings {
-        PoolSettings {
-            pool_mode: PoolMode::Transaction,
-            shards: 1,
-            user: User::default(),
-            default_role: None,
-            query_parser_enabled: false,
-            primary_reads_enabled: true,
-            sharding_function: ShardingFunction::PgBigintHash,
-        }
-    }
-}
-
-/// The globally accessible connection pool.
-#[derive(Clone, Debug, Default)]
-pub struct ConnectionPool {
-    /// The pools handled internally by bb8.
-    databases: Vec<Vec<Pool<ServerPool>>>,
-
-    /// The addresses (host, port, role) to handle
-    /// failover and load balancing deterministically.
-    addresses: Vec<Vec<Address>>,
-
-    /// List of banned addresses (see above)
-    /// that should not be queried.
-    banlist: BanList,
-
-    /// The statistics aggregator runs in a separate task
-    /// and receives stats from clients, servers, and the pool.
-    stats: Reporter,
-
-    /// The server information (K messages) have to be passed to the
-    /// clients on startup. We pre-connect to all shards and replicas
-    /// on pool creation and save the K messages here.
-    server_info: BytesMut,
-
-    /// Pool configuration.
-    pub settings: PoolSettings,
-}
-
-impl ConnectionPool {
-    /// Construct the connection pool from the configuration.
-    pub async fn from_config(client_server_map: ClientServerMap) -> Result<(), Error> {
-        let config = get_config();
-
-        let mut new_pools = HashMap::new();
-        let mut address_id = 0;
-
-        for (pool_name, pool_config) in &config.pools {
-            // There is one pool per database/user pair.
-            for (_, user) in &pool_config.users {
-                let mut shards = Vec::new();
-                let mut addresses = Vec::new();
-                let mut banlist = Vec::new();
-                let mut shard_ids = pool_config
-                    .shards
-                    .clone()
-                    .into_keys()
-                    .map(|x| x.to_string())
-                    .collect::<Vec<String>>();
-
-                // Sort by shard number to ensure consistency.
-                shard_ids.sort_by_key(|k| k.parse::<i64>().unwrap());
-
-                for shard_idx in &shard_ids {
-                    let shard = &pool_config.shards[shard_idx];
-                    let mut pools = Vec::new();
-                    let mut servers = Vec::new();
-                    let mut address_index = 0;
-                    let mut replica_number = 0;
-
-                    for server in shard.servers.iter() {
-                        let role = match server.2.as_ref() {
-                            "primary" => Role::Primary,
-                            "replica" => Role::Replica,
-                            _ => {
-                                error!("Config error: server role can be 'primary' or 'replica', have: '{}'. Defaulting to 'replica'.", server.2);
-                                Role::Replica
-                            }
-                        };
-
-                        let address = Address {
-                            id: address_id,
-                            database: shard.database.clone(),
-                            host: server.0.clone(),
-                            port: server.1 as u16,
-                            role: role,
-                            address_index,
-                            replica_number,
-                            shard: shard_idx.parse::<usize>().unwrap(),
-                            username: user.username.clone(),
-                            pool_name: pool_name.clone(),
-                        };
-
-                        address_id += 1;
-                        address_index += 1;
-
-                        if role == Role::Replica {
-                            replica_number += 1;
-                        }
-
-                        let manager = ServerPool::new(
-                            address.clone(),
-                            user.clone(),
-                            &shard.database,
-                            client_server_map.clone(),
-                            get_reporter(),
-                        );
-
-                        let pool = Pool::builder()
-                            .max_size(user.pool_size)
-                            .connection_timeout(std::time::Duration::from_millis(
-                                config.general.connect_timeout,
-                            ))
-                            .test_on_check_out(false)
-                            .build(manager)
-                            .await
-                            .unwrap();
-
-                        pools.push(pool);
-                        servers.push(address);
-                    }
-
-                    shards.push(pools);
-                    addresses.push(servers);
-                    banlist.push(HashMap::new());
-                }
-
-                assert_eq!(shards.len(), addresses.len());
-
-                let mut pool = ConnectionPool {
-                    databases: shards,
-                    addresses: addresses,
-                    banlist: Arc::new(RwLock::new(banlist)),
-                    stats: get_reporter(),
-                    server_info: BytesMut::new(),
-                    settings: PoolSettings {
-                        pool_mode: match pool_config.pool_mode.as_str() {
-                            "transaction" => PoolMode::Transaction,
-                            "session" => PoolMode::Session,
-                            _ => unreachable!(),
-                        },
-                        // shards: pool_config.shards.clone(),
-                        shards: shard_ids.len(),
-                        user: user.clone(),
-                        default_role: match pool_config.default_role.as_str() {
-                            "any" => None,
-                            "replica" => Some(Role::Replica),
-                            "primary" => Some(Role::Primary),
-                            _ => unreachable!(),
-                        },
-                        query_parser_enabled: pool_config.query_parser_enabled.clone(),
-                        primary_reads_enabled: pool_config.primary_reads_enabled,
-                        sharding_function: match pool_config.sharding_function.as_str() {
-                            "pg_bigint_hash" => ShardingFunction::PgBigintHash,
-                            "sha1" => ShardingFunction::Sha1,
-                            _ => unreachable!(),
-                        },
-                    },
-                };
-
-                // Connect to the servers to make sure pool configuration is valid
-                // before setting it globally.
-                match pool.validate().await {
-                    Ok(_) => (),
-                    Err(err) => {
-                        error!("Could not validate connection pool: {:?}", err);
-                        return Err(err);
-                    }
-                };
-
-                // There is one pool per database/user pair.
-                new_pools.insert((pool_name.clone(), user.username.clone()), pool);
-            }
-        }
-
-        POOLS.store(Arc::new(new_pools.clone()));
-
-        Ok(())
-    }
-
-    /// Connect to all shards and grab server information.
-    /// Return server information we will pass to the clients
-    /// when they connect.
-    /// This also warms up the pool for clients that connect when
-    /// the pooler starts up.
-    async fn validate(&mut self) -> Result<(), Error> {
-        let mut server_infos = Vec::new();
-        for shard in 0..self.shards() {
-            for server in 0..self.servers(shard) {
-                let connection = match self.databases[shard][server].get().await {
-                    Ok(conn) => conn,
-                    Err(err) => {
-                        error!("Shard {} down or misconfigured: {:?}", shard, err);
-                        continue;
-                    }
-                };
-
-                let proxy = connection;
-                let server = &*proxy;
-                let server_info = server.server_info();
-
-                if server_infos.len() > 0 {
-                    // Compare against the last server checked.
-                    if server_info != server_infos[server_infos.len() - 1] {
-                        warn!(
-                            "{:?} has different server configuration than the last server",
-                            proxy.address()
-                        );
-                    }
-                }
-
-                server_infos.push(server_info);
-            }
-        }
-
-        // TODO: compare server information to make sure
-        // all shards are running identical configurations.
-        if server_infos.len() == 0 {
-            return Err(Error::AllServersDown);
-        }
-
-        // We're assuming all servers are identical.
-        // TODO: not true.
-        self.server_info = server_infos[0].clone();
-
-        Ok(())
-    }
-
-    /// Get a connection from the pool.
-    pub async fn get(
-        &self,
-        shard: usize,       // shard number
-        role: Option<Role>, // primary or replica
-        process_id: i32,    // client id
-    ) -> Result<(PooledConnection<'_, ServerPool>, Address), Error> {
-        let now = Instant::now();
-        let mut candidates: Vec<&Address> = self.addresses[shard]
-            .iter()
-            .filter(|address| address.role == role)
-            .collect();
-
-        // Random load balancing
-        candidates.shuffle(&mut thread_rng());
-
-        let healthcheck_timeout = get_config().general.healthcheck_timeout;
-        let healthcheck_delay = get_config().general.healthcheck_delay as u128;
-
-        while !candidates.is_empty() {
-            // Get the next candidate
-            let address = match candidates.pop() {
-                Some(address) => address,
-                None => break,
-            };
-
-            if self.is_banned(&address, role) {
-                debug!("Address {:?} is banned", address);
-                continue;
-            }
-
-            // Indicate we're waiting on a server connection from a pool.
-            self.stats.client_waiting(process_id, address.id);
-
-            // Check if we can connect
-            let mut conn = match self.databases[address.shard][address.address_index]
-                .get()
-                .await
-            {
-                Ok(conn) => conn,
-                Err(err) => {
-                    error!("Banning instance {:?}, error: {:?}", address, err);
-                    self.ban(&address, process_id);
-                    self.stats
-                        .checkout_time(now.elapsed().as_micros(), process_id, address.id);
-                    continue;
-                }
-            };
-
-            // // Check if this server is alive with a health check.
-            let server = &mut *conn;
-
-            // Will return error if timestamp is greater than current system time, which it should never be set to
-            let require_healthcheck =
-                server.last_activity().elapsed().unwrap().as_millis() > healthcheck_delay;
-
-            // Do not issue a health check unless it's been a little while
-            // since we last checked the server is ok.
-            // Health checks are pretty expensive.
-            if !require_healthcheck {
-                self.stats
-                    .checkout_time(now.elapsed().as_micros(), process_id, address.id);
-                self.stats.server_active(conn.process_id(), address.id);
-                return Ok((conn, address.clone()));
-            }
-
-            debug!("Running health check on server {:?}", address);
-
-            self.stats.server_tested(server.process_id(), address.id);
-
-            match tokio::time::timeout(
-                tokio::time::Duration::from_millis(healthcheck_timeout),
-                server.query(";"), // Cheap query (query parser not used in PG)
-            )
-            .await
-            {
-                // Check if health check succeeded.
-                Ok(res) => match res {
-                    Ok(_) => {
-                        self.stats
-                            .checkout_time(now.elapsed().as_micros(), process_id, address.id);
-                        self.stats.server_active(conn.process_id(), address.id);
-                        return Ok((conn, address.clone()));
-                    }
-
-                    // Health check failed.
-                    Err(err) => {
-                        error!(
-                            "Banning instance {:?} because of failed health check, {:?}",
-                            address, err
-                        );
-
-                        // Don't leave a bad connection in the pool.
-                        server.mark_bad();
-
-                        self.ban(&address, process_id);
-                        continue;
-                    }
-                },
-
-                // Health check timed out.
-                Err(err) => {
-                    error!(
-                        "Banning instance {:?} because of health check timeout, {:?}",
-                        address, err
-                    );
-                    // Don't leave a bad connection in the pool.
-                    server.mark_bad();
-
-                    self.ban(&address, process_id);
-                    continue;
-                }
-            }
-        }
-
-        Err(Error::AllServersDown)
-    }
-
-    /// Ban an address (i.e. replica). It no longer will serve
-    /// traffic for any new transactions. Existing transactions on that replica
-    /// will finish successfully or error out to the clients.
-    pub fn ban(&self, address: &Address, process_id: i32) {
-        self.stats.client_disconnecting(process_id, address.id);
-
-        error!("Banning {:?}", address);
-
-        let now = chrono::offset::Utc::now().naive_utc();
-        let mut guard = self.banlist.write();
-        guard[address.shard].insert(address.clone(), now);
-    }
-
-    /// Clear the replica to receive traffic again. Takes effect immediately
-    /// for all new transactions.
-    pub fn _unban(&self, address: &Address) {
-        let mut guard = self.banlist.write();
-        guard[address.shard].remove(address);
-    }
-
-    /// Check if a replica can serve traffic. If all replicas are banned,
-    /// we unban all of them. Better to try then not to.
-    pub fn is_banned(&self, address: &Address, role: Option<Role>) -> bool {
-        let replicas_available = match role {
-            Some(Role::Replica) => self.addresses[address.shard]
-                .iter()
-                .filter(|addr| addr.role == Role::Replica)
-                .count(),
-            None => self.addresses[address.shard].len(),
-            Some(Role::Primary) => return false, // Primary cannot be banned.
-        };
-
-        debug!("Available targets for {:?}: {}", role, replicas_available);
-
-        let guard = self.banlist.read();
-
-        // Everything is banned = nothing is banned.
-        if guard[address.shard].len() == replicas_available {
-            drop(guard);
-            let mut guard = self.banlist.write();
-            guard[address.shard].clear();
-            drop(guard);
-            warn!("Unbanning all replicas.");
-            return false;
-        }
-
-        // I expect this to miss 99.9999% of the time.
-        match guard[address.shard].get(address) {
-            Some(timestamp) => {
-                let now = chrono::offset::Utc::now().naive_utc();
-                let config = get_config();
-
-                // Ban expired.
-                if now.timestamp() - timestamp.timestamp() > config.general.ban_time {
-                    drop(guard);
-                    warn!("Unbanning {:?}", address);
-                    let mut guard = self.banlist.write();
-                    guard[address.shard].remove(address);
-                    false
-                } else {
-                    debug!("{:?} is banned", address);
-                    true
-                }
-            }
-
-            None => {
-                debug!("{:?} is ok", address);
-                false
-            }
-        }
-    }
-
-    /// Get the number of configured shards.
-    pub fn shards(&self) -> usize {
-        self.databases.len()
-    }
-
-    /// Get the number of servers (primary and replicas)
-    /// configured for a shard.
-    pub fn servers(&self, shard: usize) -> usize {
-        self.addresses[shard].len()
-    }
-
-    /// Get the total number of servers (databases) we are connected to.
-    pub fn databases(&self) -> usize {
-        let mut databases = 0;
-        for shard in 0..self.shards() {
-            databases += self.servers(shard);
-        }
-        databases
-    }
-
-    /// Get pool state for a particular shard server as reported by bb8.
-    pub fn pool_state(&self, shard: usize, server: usize) -> bb8::State {
-        self.databases[shard][server].state()
-    }
-
-    /// Get the address information for a shard server.
-    pub fn address(&self, shard: usize, server: usize) -> &Address {
-        &self.addresses[shard][server]
-    }
-
-    pub fn server_info(&self) -> BytesMut {
-        self.server_info.clone()
-    }
-}
-
-/// Wrapper for the bb8 connection pool.
-pub struct ServerPool {
-    address: Address,
-    user: User,
-    database: String,
-    client_server_map: ClientServerMap,
-    stats: Reporter,
-}
-
-impl ServerPool {
-    pub fn new(
-        address: Address,
-        user: User,
-        database: &str,
-        client_server_map: ClientServerMap,
-        stats: Reporter,
-    ) -> ServerPool {
-        ServerPool {
-            address: address,
-            user: user,
-            database: database.to_string(),
-            client_server_map: client_server_map,
-            stats: stats,
-        }
-    }
-}
-
-#[async_trait]
-impl ManageConnection for ServerPool {
-    type Connection = Server;
-    type Error = Error;
-
-    /// Attempts to create a new connection.
-    async fn connect(&self) -> Result<Self::Connection, Self::Error> {
-        info!(
-            "Creating a new connection to {:?} using user {:?}",
-            self.address.name(),
-            self.user.username
-        );
-
-        // Put a temporary process_id into the stats
-        // for server login.
-        let process_id = rand::random::<i32>();
-        self.stats.server_login(process_id, self.address.id);
-
-        // Connect to the PostgreSQL server.
-        match Server::startup(
-            &self.address,
-            &self.user,
-            &self.database,
-            self.client_server_map.clone(),
-            self.stats.clone(),
-        )
-        .await
-        {
-            Ok(conn) => {
-                // Remove the temporary process_id from the stats.
-                self.stats.server_disconnecting(process_id, self.address.id);
-                Ok(conn)
-            }
-            Err(err) => {
-                // Remove the temporary process_id from the stats.
-                self.stats.server_disconnecting(process_id, self.address.id);
-                Err(err)
-            }
-        }
-    }
-
-    /// Determines if the connection is still connected to the database.
-    async fn is_valid(&self, _conn: &mut PooledConnection<'_, Self>) -> Result<(), Self::Error> {
-        Ok(())
-    }
-
-    /// Synchronously determine if the connection is no longer usable, if possible.
-    fn has_broken(&self, conn: &mut Self::Connection) -> bool {
-        conn.is_bad()
-    }
-}
-
-/// Get the connection pool
-pub fn get_pool(db: String, user: String) -> Option<ConnectionPool> {
-    match get_all_pools().get(&(db, user)) {
-        Some(pool) => Some(pool.clone()),
-        None => None,
-    }
-}
-
-/// How many total servers we have in the config.
-pub fn get_number_of_addresses() -> usize {
-    get_all_pools()
-        .iter()
-        .map(|(_, pool)| pool.databases())
-        .sum()
-}
-
-/// Get a pointer to all configured pools.
-pub fn get_all_pools() -> HashMap<(String, String), ConnectionPool> {
-    return (*(*POOLS.load())).clone();
-}
diff --git a/rust_ref/src/prometheus.rs b/rust_ref/src/prometheus.rs
deleted file mode 100644
index 4e3dc3aa..00000000
--- a/rust_ref/src/prometheus.rs
+++ /dev/null
@@ -1,210 +0,0 @@
-use hyper::service::{make_service_fn, service_fn};
-use hyper::{Body, Method, Request, Response, Server, StatusCode};
-use log::{error, info, warn};
-use phf::phf_map;
-use std::collections::HashMap;
-use std::fmt;
-use std::net::SocketAddr;
-
-use crate::config::Address;
-use crate::pool::get_all_pools;
-use crate::stats::get_stats;
-
-struct MetricHelpType {
-    help: &'static str,
-    ty: &'static str,
-}
-
-// reference for metric types: https://prometheus.io/docs/concepts/metric_types/
-// counters only increase
-// gauges can arbitrarily increase or decrease
-static METRIC_HELP_AND_TYPES_LOOKUP: phf::Map<&'static str, MetricHelpType> = phf_map! {
-    "total_query_count" => MetricHelpType {
-        help: "Number of queries sent by all clients",
-        ty: "counter",
-    },
-    "total_query_time" => MetricHelpType {
-        help: "Total amount of time for queries to execute",
-        ty: "counter",
-    },
-    "total_received" => MetricHelpType {
-        help: "Number of bytes received from the server",
-        ty: "counter",
-    },
-    "total_sent" => MetricHelpType {
-        help: "Number of bytes sent to the server",
-        ty: "counter",
-    },
-    "total_xact_count" => MetricHelpType {
-        help: "Total number of transactions started by the client",
-        ty: "counter",
-    },
-    "total_xact_time" => MetricHelpType {
-        help: "Total amount of time for all transactions to execute",
-        ty: "counter",
-    },
-    "total_wait_time" => MetricHelpType {
-        help: "Total time client waited for a server connection",
-        ty: "counter",
-    },
-    "avg_query_count" => MetricHelpType {
-        help: "Average of total_query_count every 15 seconds",
-        ty: "gauge",
-    },
-    "avg_query_time" => MetricHelpType {
-        help: "Average time taken for queries to execute every 15 seconds",
-        ty: "gauge",
-    },
-    "avg_recv" => MetricHelpType {
-        help: "Average of total_received bytes every 15 seconds",
-        ty: "gauge",
-    },
-    "avg_sent" => MetricHelpType {
-        help: "Average of total_sent bytes every 15 seconds",
-        ty: "gauge",
-    },
-    "avg_xact_count" => MetricHelpType {
-        help: "Average of total_xact_count every 15 seconds",
-        ty: "gauge",
-    },
-    "avg_xact_time" => MetricHelpType {
-        help: "Average of total_xact_time every 15 seconds",
-        ty: "gauge",
-    },
-    "avg_wait_time" => MetricHelpType {
-        help: "Average of total_wait_time every 15 seconds",
-        ty: "gauge",
-    },
-    "maxwait_us" => MetricHelpType {
-        help: "The time a client waited for a server connection in microseconds",
-        ty: "gauge",
-    },
-    "maxwait" => MetricHelpType {
-        help: "The time a client waited for a server connection in seconds",
-        ty: "gauge",
-    },
-    "cl_waiting" => MetricHelpType {
-        help: "How many clients are waiting for a connection from the pool",
-        ty: "gauge",
-    },
-    "cl_active" => MetricHelpType {
-        help: "How many clients are actively communicating with a server",
-        ty: "gauge",
-    },
-    "cl_idle" => MetricHelpType {
-        help: "How many clients are idle",
-        ty: "gauge",
-    },
-    "sv_idle" => MetricHelpType {
-        help: "How many server connections are idle",
-        ty: "gauge",
-    },
-    "sv_active" => MetricHelpType {
-        help: "How many server connections are actively communicating with a client",
-        ty: "gauge",
-    },
-    "sv_login" => MetricHelpType {
-        help: "How many server connections are currently being created",
-        ty: "gauge",
-    },
-    "sv_tested" => MetricHelpType {
-        help: "How many server connections are currently waiting on a health check to succeed",
-        ty: "gauge",
-    },
-};
-
-struct PrometheusMetric {
-    name: String,
-    help: String,
-    ty: String,
-    labels: HashMap<&'static str, String>,
-    value: i64,
-}
-
-impl fmt::Display for PrometheusMetric {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let formatted_labels = self
-            .labels
-            .iter()
-            .map(|(key, value)| format!("{}=\"{}\"", key, value))
-            .collect::<Vec<_>>()
-            .join(",");
-        write!(
-            f,
-            "# HELP {name} {help}\n# TYPE {name} {ty}\n{name}{{{formatted_labels}}} {value}\n",
-            name = format_args!("pgcat_{}", self.name),
-            help = self.help,
-            ty = self.ty,
-            formatted_labels = formatted_labels,
-            value = self.value
-        )
-    }
-}
-
-impl PrometheusMetric {
-    fn new(address: &Address, name: &str, value: i64) -> Option<PrometheusMetric> {
-        let mut labels = HashMap::new();
-        labels.insert("host", address.host.clone());
-        labels.insert("shard", address.shard.to_string());
-        labels.insert("role", address.role.to_string());
-        labels.insert("database", address.database.to_string());
-
-        METRIC_HELP_AND_TYPES_LOOKUP
-            .get(name)
-            .map(|metric| PrometheusMetric {
-                name: name.to_owned(),
-                help: metric.help.to_owned(),
-                ty: metric.ty.to_owned(),
-                labels,
-                value,
-            })
-    }
-}
-
-async fn prometheus_stats(request: Request<Body>) -> Result<Response<Body>, hyper::http::Error> {
-    match (request.method(), request.uri().path()) {
-        (&Method::GET, "/metrics") => {
-            let stats = get_stats();
-
-            let mut lines = Vec::new();
-            for (_, pool) in get_all_pools() {
-                for shard in 0..pool.shards() {
-                    for server in 0..pool.servers(shard) {
-                        let address = pool.address(shard, server);
-                        if let Some(address_stats) = stats.get(&address.id) {
-                            for (key, value) in address_stats.iter() {
-                                if let Some(prometheus_metric) =
-                                    PrometheusMetric::new(address, key, *value)
-                                {
-                                    lines.push(prometheus_metric.to_string());
-                                } else {
-                                    warn!("Metric {} not implemented for {}", key, address.name());
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
-            Response::builder()
-                .header("content-type", "text/plain; version=0.0.4")
-                .body(lines.join("\n").into())
-        }
-        _ => Response::builder()
-            .status(StatusCode::NOT_FOUND)
-            .body("".into()),
-    }
-}
-
-pub async fn start_metric_server(http_addr: SocketAddr) {
-    let http_service_factory =
-        make_service_fn(|_conn| async { Ok::<_, hyper::Error>(service_fn(prometheus_stats)) });
-    let server = Server::bind(&http_addr.into()).serve(http_service_factory);
-    info!(
-        "Exposing prometheus metrics on http://{}/metrics.",
-        http_addr
-    );
-    if let Err(e) = server.await {
-        error!("Failed to run HTTP server: {}.", e);
-    }
-}
diff --git a/rust_ref/src/query_router.rs b/rust_ref/src/query_router.rs
deleted file mode 100644
index f9d5f0b3..00000000
--- a/rust_ref/src/query_router.rs
+++ /dev/null
@@ -1,657 +0,0 @@
-/// Route queries automatically based on explicitely requested
-/// or implied query characteristics.
-use bytes::{Buf, BytesMut};
-use log::{debug, error};
-use once_cell::sync::OnceCell;
-use regex::{Regex, RegexSet};
-use sqlparser::ast::Statement::{Query, StartTransaction};
-use sqlparser::dialect::PostgreSqlDialect;
-use sqlparser::parser::Parser;
-
-use crate::config::Role;
-use crate::pool::PoolSettings;
-use crate::sharding::Sharder;
-
-/// Regexes used to parse custom commands.
-const CUSTOM_SQL_REGEXES: [&str; 7] = [
-    r"(?i)^ *SET SHARDING KEY TO '?([0-9]+)'? *;? *$",
-    r"(?i)^ *SET SHARD TO '?([0-9]+|ANY)'? *;? *$",
-    r"(?i)^ *SHOW SHARD *;? *$",
-    r"(?i)^ *SET SERVER ROLE TO '(PRIMARY|REPLICA|ANY|AUTO|DEFAULT)' *;? *$",
-    r"(?i)^ *SHOW SERVER ROLE *;? *$",
-    r"(?i)^ *SET PRIMARY READS TO '?(on|off|default)'? *;? *$",
-    r"(?i)^ *SHOW PRIMARY READS *;? *$",
-];
-
-/// Custom commands.
-#[derive(PartialEq, Debug)]
-pub enum Command {
-    SetShardingKey,
-    SetShard,
-    ShowShard,
-    SetServerRole,
-    ShowServerRole,
-    SetPrimaryReads,
-    ShowPrimaryReads,
-}
-
-/// Quickly test for match when a query is received.
-static CUSTOM_SQL_REGEX_SET: OnceCell<RegexSet> = OnceCell::new();
-
-// Get the value inside the custom command.
-static CUSTOM_SQL_REGEX_LIST: OnceCell<Vec<Regex>> = OnceCell::new();
-
-/// The query router.
-pub struct QueryRouter {
-    /// Which shard we should be talking to right now.
-    active_shard: Option<usize>,
-
-    /// Which server should we be talking to.
-    active_role: Option<Role>,
-
-    /// Should we try to parse queries to route them to replicas or primary automatically
-    query_parser_enabled: bool,
-
-    /// Include the primary into the replica pool for reads.
-    primary_reads_enabled: bool,
-
-    /// Pool configuration.
-    pool_settings: PoolSettings,
-}
-
-impl QueryRouter {
-    /// One-time initialization of regexes
-    /// that parse our custom SQL protocol.
-    pub fn setup() -> bool {
-        let set = match RegexSet::new(&CUSTOM_SQL_REGEXES) {
-            Ok(rgx) => rgx,
-            Err(err) => {
-                error!("QueryRouter::setup Could not compile regex set: {:?}", err);
-                return false;
-            }
-        };
-
-        let list: Vec<_> = CUSTOM_SQL_REGEXES
-            .iter()
-            .map(|rgx| Regex::new(rgx).unwrap())
-            .collect();
-
-        assert_eq!(list.len(), set.len());
-
-        match CUSTOM_SQL_REGEX_LIST.set(list) {
-            Ok(_) => true,
-            Err(_) => return false,
-        };
-
-        match CUSTOM_SQL_REGEX_SET.set(set) {
-            Ok(_) => true,
-            Err(_) => false,
-        }
-    }
-
-    /// Create a new instance of the query router.
-    /// Each client gets its own.
-    pub fn new() -> QueryRouter {
-        QueryRouter {
-            active_shard: None,
-            active_role: None,
-            query_parser_enabled: false,
-            primary_reads_enabled: false,
-            pool_settings: PoolSettings::default(),
-        }
-    }
-
-    /// Pool settings can change because of a config reload.
-    pub fn update_pool_settings(&mut self, pool_settings: PoolSettings) {
-        self.pool_settings = pool_settings;
-    }
-
-    /// Try to parse a command and execute it.
-    pub fn try_execute_command(&mut self, mut buf: BytesMut) -> Option<(Command, String)> {
-        let code = buf.get_u8() as char;
-
-        // Only simple protocol supported for commands.
-        if code != 'Q' {
-            return None;
-        }
-
-        let len = buf.get_i32() as usize;
-        let query = String::from_utf8_lossy(&buf[..len - 5]).to_string(); // Ignore the terminating NULL.
-
-        let regex_set = match CUSTOM_SQL_REGEX_SET.get() {
-            Some(regex_set) => regex_set,
-            None => return None,
-        };
-
-        let regex_list = match CUSTOM_SQL_REGEX_LIST.get() {
-            Some(regex_list) => regex_list,
-            None => return None,
-        };
-
-        let matches: Vec<_> = regex_set.matches(&query).into_iter().collect();
-
-        // This is not a custom query, try to infer which
-        // server it'll go to if the query parser is enabled.
-        if matches.len() != 1 {
-            debug!("Regular query, not a command");
-            return None;
-        }
-
-        let command = match matches[0] {
-            0 => Command::SetShardingKey,
-            1 => Command::SetShard,
-            2 => Command::ShowShard,
-            3 => Command::SetServerRole,
-            4 => Command::ShowServerRole,
-            5 => Command::SetPrimaryReads,
-            6 => Command::ShowPrimaryReads,
-            _ => unreachable!(),
-        };
-
-        let mut value = match command {
-            Command::SetShardingKey
-            | Command::SetShard
-            | Command::SetServerRole
-            | Command::SetPrimaryReads => {
-                // Capture value. I know this re-runs the regex engine, but I haven't
-                // figured out a better way just yet. I think I can write a single Regex
-                // that matches all 5 custom SQL patterns, but maybe that's not very legible?
-                //
-                // I think this is faster than running the Regex engine 5 times.
-                match regex_list[matches[0]].captures(&query) {
-                    Some(captures) => match captures.get(1) {
-                        Some(value) => value.as_str().to_string(),
-                        None => return None,
-                    },
-                    None => return None,
-                }
-            }
-
-            Command::ShowShard => self.shard().to_string(),
-            Command::ShowServerRole => match self.active_role {
-                Some(Role::Primary) => String::from("primary"),
-                Some(Role::Replica) => String::from("replica"),
-                None => {
-                    if self.query_parser_enabled {
-                        String::from("auto")
-                    } else {
-                        String::from("any")
-                    }
-                }
-            },
-
-            Command::ShowPrimaryReads => match self.primary_reads_enabled {
-                true => String::from("on"),
-                false => String::from("off"),
-            },
-        };
-
-        match command {
-            Command::SetShardingKey => {
-                let sharder = Sharder::new(
-                    self.pool_settings.shards,
-                    self.pool_settings.sharding_function,
-                );
-                let shard = sharder.shard(value.parse::<i64>().unwrap());
-                self.active_shard = Some(shard);
-                value = shard.to_string();
-            }
-
-            Command::SetShard => {
-                self.active_shard = match value.to_ascii_uppercase().as_ref() {
-                    "ANY" => Some(rand::random::<usize>() % self.pool_settings.shards),
-                    _ => Some(value.parse::<usize>().unwrap()),
-                };
-            }
-
-            Command::SetServerRole => {
-                self.active_role = match value.to_ascii_lowercase().as_ref() {
-                    "primary" => {
-                        self.query_parser_enabled = false;
-                        Some(Role::Primary)
-                    }
-
-                    "replica" => {
-                        self.query_parser_enabled = false;
-                        Some(Role::Replica)
-                    }
-
-                    "any" => {
-                        self.query_parser_enabled = false;
-                        None
-                    }
-
-                    "auto" => {
-                        self.query_parser_enabled = true;
-                        None
-                    }
-
-                    "default" => {
-                        self.active_role = self.pool_settings.default_role;
-                        self.query_parser_enabled = self.query_parser_enabled;
-                        self.active_role
-                    }
-
-                    _ => unreachable!(),
-                };
-            }
-
-            Command::SetPrimaryReads => {
-                if value == "on" {
-                    debug!("Setting primary reads to on");
-                    self.primary_reads_enabled = true;
-                } else if value == "off" {
-                    debug!("Setting primary reads to off");
-                    self.primary_reads_enabled = false;
-                } else if value == "default" {
-                    debug!("Setting primary reads to default");
-                    self.primary_reads_enabled = self.pool_settings.primary_reads_enabled;
-                }
-            }
-
-            _ => (),
-        }
-
-        Some((command, value))
-    }
-
-    /// Try to infer which server to connect to based on the contents of the query.
-    pub fn infer_role(&mut self, mut buf: BytesMut) -> bool {
-        debug!("Inferring role");
-
-        let code = buf.get_u8() as char;
-        let len = buf.get_i32() as usize;
-
-        let query = match code {
-            // Query
-            'Q' => {
-                let query = String::from_utf8_lossy(&buf[..len - 5]).to_string();
-                debug!("Query: '{}'", query);
-                query
-            }
-
-            // Parse (prepared statement)
-            'P' => {
-                let mut start = 0;
-                let mut end;
-
-                // Skip the name of the prepared statement.
-                while buf[start] != 0 && start < buf.len() {
-                    start += 1;
-                }
-                start += 1; // Skip terminating null
-
-                // Find the end of the prepared stmt (\0)
-                end = start;
-                while buf[end] != 0 && end < buf.len() {
-                    end += 1;
-                }
-
-                let query = String::from_utf8_lossy(&buf[start..end]).to_string();
-
-                debug!("Prepared statement: '{}'", query);
-
-                query.replace("$", "") // Remove placeholders turning them into "values"
-            }
-
-            _ => return false,
-        };
-
-        let ast = match Parser::parse_sql(&PostgreSqlDialect {}, &query) {
-            Ok(ast) => ast,
-            Err(err) => {
-                debug!("{}", err.to_string());
-                return false;
-            }
-        };
-
-        if ast.len() == 0 {
-            return false;
-        }
-
-        match ast[0] {
-            // All transactions go to the primary, probably a write.
-            StartTransaction { .. } => {
-                self.active_role = Some(Role::Primary);
-            }
-
-            // Likely a read-only query
-            Query { .. } => {
-                self.active_role = match self.primary_reads_enabled {
-                    false => Some(Role::Replica), // If primary should not be receiving reads, use a replica.
-                    true => None,                 // Any server role is fine in this case.
-                }
-            }
-
-            // Likely a write
-            _ => {
-                self.active_role = Some(Role::Primary);
-            }
-        };
-
-        true
-    }
-
-    /// Get the current desired server role we should be talking to.
-    pub fn role(&self) -> Option<Role> {
-        self.active_role
-    }
-
-    /// Get desired shard we should be talking to.
-    pub fn shard(&self) -> usize {
-        match self.active_shard {
-            Some(shard) => shard,
-            None => 0,
-        }
-    }
-
-    pub fn set_shard(&mut self, shard: usize) {
-        self.active_shard = Some(shard);
-    }
-
-    /// Should we attempt to parse queries?
-    #[allow(dead_code)]
-    pub fn query_parser_enabled(&self) -> bool {
-        self.query_parser_enabled
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-    use crate::messages::simple_query;
-    use crate::pool::PoolMode;
-    use crate::sharding::ShardingFunction;
-    use bytes::BufMut;
-
-    #[test]
-    fn test_defaults() {
-        QueryRouter::setup();
-        let qr = QueryRouter::new();
-
-        assert_eq!(qr.role(), None);
-    }
-
-    #[test]
-    fn test_infer_role_replica() {
-        QueryRouter::setup();
-        let mut qr = QueryRouter::new();
-        assert!(qr.try_execute_command(simple_query("SET SERVER ROLE TO 'auto'")) != None);
-        assert_eq!(qr.query_parser_enabled(), true);
-
-        assert!(qr.try_execute_command(simple_query("SET PRIMARY READS TO off")) != None);
-
-        let queries = vec![
-            simple_query("SELECT * FROM items WHERE id = 5"),
-            simple_query(
-                "SELECT id, name, value FROM items INNER JOIN prices ON item.id = prices.item_id",
-            ),
-            simple_query("WITH t AS (SELECT * FROM items) SELECT * FROM t"),
-        ];
-
-        for query in queries {
-            // It's a recognized query
-            assert!(qr.infer_role(query));
-            assert_eq!(qr.role(), Some(Role::Replica));
-        }
-    }
-
-    #[test]
-    fn test_infer_role_primary() {
-        QueryRouter::setup();
-        let mut qr = QueryRouter::new();
-
-        let queries = vec![
-            simple_query("UPDATE items SET name = 'pumpkin' WHERE id = 5"),
-            simple_query("INSERT INTO items (id, name) VALUES (5, 'pumpkin')"),
-            simple_query("DELETE FROM items WHERE id = 5"),
-            simple_query("BEGIN"), // Transaction start
-        ];
-
-        for query in queries {
-            // It's a recognized query
-            assert!(qr.infer_role(query));
-            assert_eq!(qr.role(), Some(Role::Primary));
-        }
-    }
-
-    #[test]
-    fn test_infer_role_primary_reads_enabled() {
-        QueryRouter::setup();
-        let mut qr = QueryRouter::new();
-        let query = simple_query("SELECT * FROM items WHERE id = 5");
-        assert!(qr.try_execute_command(simple_query("SET PRIMARY READS TO on")) != None);
-
-        assert!(qr.infer_role(query));
-        assert_eq!(qr.role(), None);
-    }
-
-    #[test]
-    fn test_infer_role_parse_prepared() {
-        QueryRouter::setup();
-        let mut qr = QueryRouter::new();
-        qr.try_execute_command(simple_query("SET SERVER ROLE TO 'auto'"));
-        assert!(qr.try_execute_command(simple_query("SET PRIMARY READS TO off")) != None);
-
-        let prepared_stmt = BytesMut::from(
-            &b"WITH t AS (SELECT * FROM items WHERE name = $1) SELECT * FROM t WHERE id = $2\0"[..],
-        );
-        let mut res = BytesMut::from(&b"P"[..]);
-        res.put_i32(prepared_stmt.len() as i32 + 4 + 1 + 2);
-        res.put_u8(0);
-        res.put(prepared_stmt);
-        res.put_i16(0);
-
-        assert!(qr.infer_role(res));
-        assert_eq!(qr.role(), Some(Role::Replica));
-    }
-
-    #[test]
-    fn test_regex_set() {
-        QueryRouter::setup();
-
-        let tests = [
-            // Upper case
-            "SET SHARDING KEY TO '1'",
-            "SET SHARD TO '1'",
-            "SHOW SHARD",
-            "SET SERVER ROLE TO 'replica'",
-            "SET SERVER ROLE TO 'primary'",
-            "SET SERVER ROLE TO 'any'",
-            "SET SERVER ROLE TO 'auto'",
-            "SHOW SERVER ROLE",
-            "SET PRIMARY READS TO 'on'",
-            "SET PRIMARY READS TO 'off'",
-            "SET PRIMARY READS TO 'default'",
-            "SHOW PRIMARY READS",
-            // Lower case
-            "set sharding key to '1'",
-            "set shard to '1'",
-            "show shard",
-            "set server role to 'replica'",
-            "set server role to 'primary'",
-            "set server role to 'any'",
-            "set server role to 'auto'",
-            "show server role",
-            "set primary reads to 'on'",
-            "set primary reads to 'OFF'",
-            "set primary reads to 'deFaUlt'",
-            // No quotes
-            "SET SHARDING KEY TO 11235",
-            "SET SHARD TO 15",
-            "SET PRIMARY READS TO off",
-            // Spaces and semicolon
-            "  SET SHARDING KEY TO 11235  ; ",
-            "  SET SHARD TO 15;   ",
-            "  SET SHARDING KEY TO 11235  ;",
-            " SET SERVER ROLE TO 'primary';   ",
-            "    SET SERVER ROLE TO 'primary'  ; ",
-            "  SET SERVER ROLE TO 'primary'  ;",
-            "  SET PRIMARY READS TO 'off'    ;",
-        ];
-
-        // Which regexes it'll match to in the list
-        let matches = [
-            0, 1, 2, 3, 3, 3, 3, 4, 5, 5, 5, 6, 0, 1, 2, 3, 3, 3, 3, 4, 5, 5, 5, 0, 1, 5, 0, 1, 0,
-            3, 3, 3, 5,
-        ];
-
-        let list = CUSTOM_SQL_REGEX_LIST.get().unwrap();
-        let set = CUSTOM_SQL_REGEX_SET.get().unwrap();
-
-        for (i, test) in tests.iter().enumerate() {
-            if !list[matches[i]].is_match(test) {
-                println!("{} does not match {}", test, list[matches[i]]);
-                assert!(false);
-            }
-            assert_eq!(set.matches(test).into_iter().collect::<Vec<_>>().len(), 1);
-        }
-
-        let bad = [
-            "SELECT * FROM table",
-            "SELECT * FROM table WHERE value = 'set sharding key to 5'", // Don't capture things in the middle of the query
-        ];
-
-        for query in &bad {
-            assert_eq!(set.matches(query).into_iter().collect::<Vec<_>>().len(), 0);
-        }
-    }
-
-    #[test]
-    fn test_try_execute_command() {
-        QueryRouter::setup();
-        let mut qr = QueryRouter::new();
-
-        // SetShardingKey
-        let query = simple_query("SET SHARDING KEY TO 13");
-        assert_eq!(
-            qr.try_execute_command(query),
-            Some((Command::SetShardingKey, String::from("0")))
-        );
-        assert_eq!(qr.shard(), 0);
-
-        // SetShard
-        let query = simple_query("SET SHARD TO '1'");
-        assert_eq!(
-            qr.try_execute_command(query),
-            Some((Command::SetShard, String::from("1")))
-        );
-        assert_eq!(qr.shard(), 1);
-
-        // ShowShard
-        let query = simple_query("SHOW SHARD");
-        assert_eq!(
-            qr.try_execute_command(query),
-            Some((Command::ShowShard, String::from("1")))
-        );
-
-        // SetServerRole
-        let roles = ["primary", "replica", "any", "auto", "primary"];
-        let verify_roles = [
-            Some(Role::Primary),
-            Some(Role::Replica),
-            None,
-            None,
-            Some(Role::Primary),
-        ];
-        let query_parser_enabled = [false, false, false, true, false];
-
-        for (idx, role) in roles.iter().enumerate() {
-            let query = simple_query(&format!("SET SERVER ROLE TO '{}'", role));
-            assert_eq!(
-                qr.try_execute_command(query),
-                Some((Command::SetServerRole, String::from(*role)))
-            );
-            assert_eq!(qr.role(), verify_roles[idx],);
-            assert_eq!(qr.query_parser_enabled(), query_parser_enabled[idx],);
-
-            // ShowServerRole
-            let query = simple_query("SHOW SERVER ROLE");
-            assert_eq!(
-                qr.try_execute_command(query),
-                Some((Command::ShowServerRole, String::from(*role)))
-            );
-        }
-
-        let primary_reads = ["on", "off", "default"];
-        let primary_reads_enabled = ["on", "off", "on"];
-
-        for (idx, primary_reads) in primary_reads.iter().enumerate() {
-            assert_eq!(
-                qr.try_execute_command(simple_query(&format!(
-                    "SET PRIMARY READS TO {}",
-                    primary_reads
-                ))),
-                Some((Command::SetPrimaryReads, String::from(*primary_reads)))
-            );
-            assert_eq!(
-                qr.try_execute_command(simple_query("SHOW PRIMARY READS")),
-                Some((
-                    Command::ShowPrimaryReads,
-                    String::from(primary_reads_enabled[idx])
-                ))
-            );
-        }
-    }
-
-    #[test]
-    fn test_enable_query_parser() {
-        QueryRouter::setup();
-        let mut qr = QueryRouter::new();
-        let query = simple_query("SET SERVER ROLE TO 'auto'");
-        assert!(qr.try_execute_command(simple_query("SET PRIMARY READS TO off")) != None);
-
-        assert!(qr.try_execute_command(query) != None);
-        assert!(qr.query_parser_enabled());
-        assert_eq!(qr.role(), None);
-
-        let query = simple_query("INSERT INTO test_table VALUES (1)");
-        assert_eq!(qr.infer_role(query), true);
-        assert_eq!(qr.role(), Some(Role::Primary));
-
-        let query = simple_query("SELECT * FROM test_table");
-        assert_eq!(qr.infer_role(query), true);
-        assert_eq!(qr.role(), Some(Role::Replica));
-
-        assert!(qr.query_parser_enabled());
-        let query = simple_query("SET SERVER ROLE TO 'default'");
-        assert!(qr.try_execute_command(query) != None);
-        assert!(qr.query_parser_enabled());
-    }
-
-    #[test]
-    fn test_update_from_pool_settings() {
-        QueryRouter::setup();
-
-        let pool_settings = PoolSettings {
-            pool_mode: PoolMode::Transaction,
-            shards: 0,
-            user: crate::config::User::default(),
-            default_role: Some(Role::Replica),
-            query_parser_enabled: true,
-            primary_reads_enabled: false,
-            sharding_function: ShardingFunction::PgBigintHash,
-        };
-        let mut qr = QueryRouter::new();
-        assert_eq!(qr.active_role, None);
-        assert_eq!(qr.active_shard, None);
-        assert_eq!(qr.query_parser_enabled, false);
-        assert_eq!(qr.primary_reads_enabled, false);
-
-        // Internal state must not be changed due to this, only defaults
-        qr.update_pool_settings(pool_settings.clone());
-
-        assert_eq!(qr.active_role, None);
-        assert_eq!(qr.active_shard, None);
-        assert_eq!(qr.query_parser_enabled, false);
-        assert_eq!(qr.primary_reads_enabled, false);
-
-        let q1 = simple_query("SET SERVER ROLE TO 'primary'");
-        assert!(qr.try_execute_command(q1) != None);
-        assert_eq!(qr.active_role.unwrap(), Role::Primary);
-
-        let q2 = simple_query("SET SERVER ROLE TO 'default'");
-        assert!(qr.try_execute_command(q2) != None);
-        assert_eq!(qr.active_role.unwrap(), pool_settings.clone().default_role);
-    }
-}
diff --git a/rust_ref/src/scram.rs b/rust_ref/src/scram.rs
deleted file mode 100644
index 514ed7a1..00000000
--- a/rust_ref/src/scram.rs
+++ /dev/null
@@ -1,320 +0,0 @@
-// SCRAM-SHA-256 authentication. Heavily inspired by
-// https://github.com/sfackler/rust-postgres/
-// SASL implementation.
-
-use bytes::BytesMut;
-use hmac::{Hmac, Mac};
-use rand::{self, Rng};
-use sha2::digest::FixedOutput;
-use sha2::{Digest, Sha256};
-
-use std::fmt::Write;
-
-use crate::constants::*;
-use crate::errors::Error;
-
-/// Normalize a password string. Postgres
-/// passwords don't have to be UTF-8.
-fn normalize(pass: &[u8]) -> Vec<u8> {
-    let pass = match std::str::from_utf8(pass) {
-        Ok(pass) => pass,
-        Err(_) => return pass.to_vec(),
-    };
-
-    match stringprep::saslprep(pass) {
-        Ok(pass) => pass.into_owned().into_bytes(),
-        Err(_) => pass.as_bytes().to_vec(),
-    }
-}
-
-/// Keep the SASL state through the exchange.
-/// It takes 3 messages to complete the authentication.
-pub struct ScramSha256 {
-    password: String,
-    salted_password: [u8; 32],
-    auth_message: String,
-    message: BytesMut,
-    nonce: String,
-}
-
-impl ScramSha256 {
-    /// Create the Scram state from a password. It'll automatically
-    /// generate a nonce.
-    pub fn new(password: &str) -> ScramSha256 {
-        let mut rng = rand::thread_rng();
-        let nonce = (0..NONCE_LENGTH)
-            .map(|_| {
-                let mut v = rng.gen_range(0x21u8..0x7e);
-                if v == 0x2c {
-                    v = 0x7e
-                }
-                v as char
-            })
-            .collect::<String>();
-
-        Self::from_nonce(password, &nonce)
-    }
-
-    /// Used for testing.
-    pub fn from_nonce(password: &str, nonce: &str) -> ScramSha256 {
-        let message = BytesMut::from(&format!("{}n=,r={}", "n,,", nonce).as_bytes()[..]);
-
-        ScramSha256 {
-            password: password.to_string(),
-            nonce: String::from(nonce),
-            message,
-            salted_password: [0u8; 32],
-            auth_message: String::new(),
-        }
-    }
-
-    /// Get the current state of the SASL authentication.
-    pub fn message(&mut self) -> BytesMut {
-        self.message.clone()
-    }
-
-    /// Update the state with message received from server.
-    pub fn update(&mut self, message: &BytesMut) -> Result<BytesMut, Error> {
-        let server_message = Message::parse(message)?;
-
-        if !server_message.nonce.starts_with(&self.nonce) {
-            return Err(Error::ProtocolSyncError);
-        }
-
-        let salt = match base64::decode(&server_message.salt) {
-            Ok(salt) => salt,
-            Err(_) => return Err(Error::ProtocolSyncError),
-        };
-
-        let salted_password = Self::hi(
-            &normalize(&self.password.as_bytes()[..]),
-            &salt,
-            server_message.iterations,
-        );
-
-        // Save for verification of final server message.
-        self.salted_password = salted_password;
-
-        let mut hmac = match Hmac::<Sha256>::new_from_slice(&salted_password) {
-            Ok(hmac) => hmac,
-            Err(_) => return Err(Error::ServerError),
-        };
-
-        hmac.update(b"Client Key");
-
-        let client_key = hmac.finalize().into_bytes();
-
-        let mut hash = Sha256::default();
-        hash.update(client_key.as_slice());
-
-        let stored_key = hash.finalize_fixed();
-        let mut cbind_input = vec![];
-        cbind_input.extend("n,,".as_bytes());
-
-        let cbind_input = base64::encode(&cbind_input);
-
-        self.message.clear();
-
-        // Start writing the client reply.
-        match write!(
-            &mut self.message,
-            "c={},r={}",
-            cbind_input, server_message.nonce
-        ) {
-            Ok(_) => (),
-            Err(_) => return Err(Error::ServerError),
-        };
-
-        let auth_message = format!(
-            "n=,r={},{},{}",
-            self.nonce,
-            String::from_utf8_lossy(&message[..]),
-            String::from_utf8_lossy(&self.message[..])
-        );
-
-        let mut hmac = match Hmac::<Sha256>::new_from_slice(&stored_key) {
-            Ok(hmac) => hmac,
-            Err(_) => return Err(Error::ServerError),
-        };
-        hmac.update(auth_message.as_bytes());
-
-        // Save the auth message for server final message verification.
-        self.auth_message = auth_message;
-
-        let client_signature = hmac.finalize().into_bytes();
-
-        // Sign the client proof.
-        let mut client_proof = client_key;
-        for (proof, signature) in client_proof.iter_mut().zip(client_signature) {
-            *proof ^= signature;
-        }
-
-        match write!(&mut self.message, ",p={}", base64::encode(&*client_proof)) {
-            Ok(_) => (),
-            Err(_) => return Err(Error::ServerError),
-        };
-
-        Ok(self.message.clone())
-    }
-
-    /// Verify final server message.
-    pub fn finish(&mut self, message: &BytesMut) -> Result<(), Error> {
-        let final_message = FinalMessage::parse(message)?;
-
-        let verifier = match base64::decode(&final_message.value) {
-            Ok(verifier) => verifier,
-            Err(_) => return Err(Error::ProtocolSyncError),
-        };
-
-        let mut hmac = match Hmac::<Sha256>::new_from_slice(&self.salted_password) {
-            Ok(hmac) => hmac,
-            Err(_) => return Err(Error::ServerError),
-        };
-        hmac.update(b"Server Key");
-        let server_key = hmac.finalize().into_bytes();
-
-        let mut hmac = match Hmac::<Sha256>::new_from_slice(&server_key) {
-            Ok(hmac) => hmac,
-            Err(_) => return Err(Error::ServerError),
-        };
-        hmac.update(self.auth_message.as_bytes());
-
-        match hmac.verify_slice(&verifier) {
-            Ok(_) => Ok(()),
-            Err(_) => return Err(Error::ServerError),
-        }
-    }
-
-    /// Hash the password with the salt i-times.
-    fn hi(str: &[u8], salt: &[u8], i: u32) -> [u8; 32] {
-        let mut hmac =
-            Hmac::<Sha256>::new_from_slice(str).expect("HMAC is able to accept all key sizes");
-        hmac.update(salt);
-        hmac.update(&[0, 0, 0, 1]);
-        let mut prev = hmac.finalize().into_bytes();
-
-        let mut hi = prev;
-
-        for _ in 1..i {
-            let mut hmac = Hmac::<Sha256>::new_from_slice(str).expect("already checked above");
-            hmac.update(&prev);
-            prev = hmac.finalize().into_bytes();
-
-            for (hi, prev) in hi.iter_mut().zip(prev) {
-                *hi ^= prev;
-            }
-        }
-
-        hi.into()
-    }
-}
-
-/// Parse the server challenge.
-struct Message {
-    nonce: String,
-    salt: String,
-    iterations: u32,
-}
-
-impl Message {
-    /// Parse the server SASL challenge.
-    fn parse(message: &BytesMut) -> Result<Message, Error> {
-        let parts = String::from_utf8_lossy(&message[..])
-            .split(",")
-            .map(|s| s.to_string())
-            .collect::<Vec<String>>();
-
-        if parts.len() != 3 {
-            return Err(Error::ProtocolSyncError);
-        }
-
-        let nonce = str::replace(&parts[0], "r=", "");
-        let salt = str::replace(&parts[1], "s=", "");
-        let iterations = match str::replace(&parts[2], "i=", "").parse::<u32>() {
-            Ok(iterations) => iterations,
-            Err(_) => return Err(Error::ProtocolSyncError),
-        };
-
-        Ok(Message {
-            nonce,
-            salt,
-            iterations,
-        })
-    }
-}
-
-/// Parse server final validation message.
-struct FinalMessage {
-    value: String,
-}
-
-impl FinalMessage {
-    /// Parse the server final validation message.
-    pub fn parse(message: &BytesMut) -> Result<FinalMessage, Error> {
-        if !message.starts_with(b"v=") || message.len() < 4 {
-            return Err(Error::ProtocolSyncError);
-        }
-
-        Ok(FinalMessage {
-            value: String::from_utf8_lossy(&message[2..]).to_string(),
-        })
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    fn parse_server_first_message() {
-        let message = BytesMut::from(
-            &"r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096".as_bytes()[..],
-        );
-        let message = Message::parse(&message).unwrap();
-        assert_eq!(message.nonce, "fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j");
-        assert_eq!(message.salt, "QSXCR+Q6sek8bf92");
-        assert_eq!(message.iterations, 4096);
-    }
-
-    #[test]
-    fn parse_server_last_message() {
-        let f = FinalMessage::parse(&BytesMut::from(
-            &"v=U+ppxD5XUKtradnv8e2MkeupiA8FU87Sg8CXzXHDAzw".as_bytes()[..],
-        ))
-        .unwrap();
-        assert_eq!(
-            f.value,
-            "U+ppxD5XUKtradnv8e2MkeupiA8FU87Sg8CXzXHDAzw".to_string()
-        );
-    }
-
-    // recorded auth exchange from psql
-    #[test]
-    fn exchange() {
-        let password = "foobar";
-        let nonce = "9IZ2O01zb9IgiIZ1WJ/zgpJB";
-
-        let client_first = "n,,n=,r=9IZ2O01zb9IgiIZ1WJ/zgpJB";
-        let server_first =
-            "r=9IZ2O01zb9IgiIZ1WJ/zgpJBjx/oIRLs02gGSHcw1KEty3eY,s=fs3IXBy7U7+IvVjZ,i\
-             =4096";
-        let client_final =
-            "c=biws,r=9IZ2O01zb9IgiIZ1WJ/zgpJBjx/oIRLs02gGSHcw1KEty3eY,p=AmNKosjJzS3\
-             1NTlQYNs5BTeQjdHdk7lOflDo5re2an8=";
-        let server_final = "v=U+ppxD5XUKtradnv8e2MkeupiA8FU87Sg8CXzXHDAzw=";
-
-        let mut scram = ScramSha256::from_nonce(password, nonce);
-
-        let message = scram.message();
-        assert_eq!(std::str::from_utf8(&message).unwrap(), client_first);
-
-        let result = scram
-            .update(&BytesMut::from(&server_first.as_bytes()[..]))
-            .unwrap();
-        assert_eq!(std::str::from_utf8(&result).unwrap(), client_final);
-
-        scram
-            .finish(&BytesMut::from(&server_final.as_bytes()[..]))
-            .unwrap();
-    }
-}
diff --git a/rust_ref/src/server.rs b/rust_ref/src/server.rs
deleted file mode 100644
index 3134a65d..00000000
--- a/rust_ref/src/server.rs
+++ /dev/null
@@ -1,614 +0,0 @@
-/// Implementation of the PostgreSQL server (database) protocol.
-/// Here we are pretending to the a Postgres client.
-use bytes::{Buf, BufMut, BytesMut};
-use log::{debug, error, info, trace};
-use std::time::SystemTime;
-use tokio::io::{AsyncReadExt, BufReader};
-use tokio::net::{
-    tcp::{OwnedReadHalf, OwnedWriteHalf},
-    TcpStream,
-};
-
-use crate::config::{Address, User};
-use crate::constants::*;
-use crate::errors::Error;
-use crate::messages::*;
-use crate::scram::ScramSha256;
-use crate::stats::Reporter;
-use crate::ClientServerMap;
-
-/// Server state.
-pub struct Server {
-    /// Server host, e.g. localhost,
-    /// port, e.g. 5432, and role, e.g. primary or replica.
-    address: Address,
-
-    /// Buffered read socket.
-    read: BufReader<OwnedReadHalf>,
-
-    /// Unbuffered write socket (our client code buffers).
-    write: OwnedWriteHalf,
-
-    /// Our server response buffer. We buffer data before we give it to the client.
-    buffer: BytesMut,
-
-    /// Server information the server sent us over on startup.
-    server_info: BytesMut,
-
-    /// Backend id and secret key used for query cancellation.
-    process_id: i32,
-    secret_key: i32,
-
-    /// Is the server inside a transaction or idle.
-    in_transaction: bool,
-
-    /// Is there more data for the client to read.
-    data_available: bool,
-
-    /// Is the server broken? We'll remote it from the pool if so.
-    bad: bool,
-
-    /// Mapping of clients and servers used for query cancellation.
-    client_server_map: ClientServerMap,
-
-    /// Server connected at.
-    connected_at: chrono::naive::NaiveDateTime,
-
-    /// Reports various metrics, e.g. data sent & received.
-    stats: Reporter,
-
-    /// Application name using the server at the moment.
-    application_name: String,
-
-    // Last time that a successful server send or response happened
-    last_activity: SystemTime,
-}
-
-impl Server {
-    /// Pretend to be the Postgres client and connect to the server given host, port and credentials.
-    /// Perform the authentication and return the server in a ready for query state.
-    pub async fn startup(
-        address: &Address,
-        user: &User,
-        database: &str,
-        client_server_map: ClientServerMap,
-        stats: Reporter,
-    ) -> Result<Server, Error> {
-        let mut stream =
-            match TcpStream::connect(&format!("{}:{}", &address.host, address.port)).await {
-                Ok(stream) => stream,
-                Err(err) => {
-                    error!("Could not connect to server: {}", err);
-                    return Err(Error::SocketError);
-                }
-            };
-
-        trace!("Sending StartupMessage");
-
-        // StartupMessage
-        startup(&mut stream, &user.username, database).await?;
-
-        let mut server_info = BytesMut::new();
-        let mut process_id: i32 = 0;
-        let mut secret_key: i32 = 0;
-
-        // We'll be handling multiple packets, but they will all be structured the same.
-        // We'll loop here until this exchange is complete.
-        let mut scram = ScramSha256::new(&user.password);
-
-        loop {
-            let code = match stream.read_u8().await {
-                Ok(code) => code as char,
-                Err(_) => return Err(Error::SocketError),
-            };
-
-            let len = match stream.read_i32().await {
-                Ok(len) => len,
-                Err(_) => return Err(Error::SocketError),
-            };
-
-            trace!("Message: {}", code);
-
-            match code {
-                // Authentication
-                'R' => {
-                    // Determine which kind of authentication is required, if any.
-                    let auth_code = match stream.read_i32().await {
-                        Ok(auth_code) => auth_code,
-                        Err(_) => return Err(Error::SocketError),
-                    };
-
-                    trace!("Auth: {}", auth_code);
-
-                    match auth_code {
-                        MD5_ENCRYPTED_PASSWORD => {
-                            // The salt is 4 bytes.
-                            // See: https://www.postgresql.org/docs/12/protocol-message-formats.html
-                            let mut salt = vec![0u8; 4];
-
-                            match stream.read_exact(&mut salt).await {
-                                Ok(_) => (),
-                                Err(_) => return Err(Error::SocketError),
-                            };
-
-                            md5_password(&mut stream, &user.username, &user.password, &salt[..])
-                                .await?;
-                        }
-
-                        AUTHENTICATION_SUCCESSFUL => (),
-
-                        SASL => {
-                            debug!("Starting SASL authentication");
-                            let sasl_len = (len - 8) as usize;
-                            let mut sasl_auth = vec![0u8; sasl_len];
-
-                            match stream.read_exact(&mut sasl_auth).await {
-                                Ok(_) => (),
-                                Err(_) => return Err(Error::SocketError),
-                            };
-
-                            let sasl_type = String::from_utf8_lossy(&sasl_auth[..sasl_len - 2]);
-
-                            if sasl_type == SCRAM_SHA_256 {
-                                debug!("Using {}", SCRAM_SHA_256);
-
-                                // Generate client message.
-                                let sasl_response = scram.message();
-
-                                // SASLInitialResponse (F)
-                                let mut res = BytesMut::new();
-                                res.put_u8(b'p');
-
-                                // length + String length + length + length of sasl response
-                                res.put_i32(
-                                    4 // i32 size
-                                        + SCRAM_SHA_256.len() as i32 // length of SASL version string,
-                                        + 1 // Null terminator for the SASL version string,
-                                        + 4 // i32 size
-                                        + sasl_response.len() as i32, // length of SASL response
-                                );
-
-                                res.put_slice(&format!("{}\0", SCRAM_SHA_256).as_bytes()[..]);
-                                res.put_i32(sasl_response.len() as i32);
-                                res.put(sasl_response);
-
-                                write_all(&mut stream, res).await?;
-                            } else {
-                                error!("Unsupported SCRAM version: {}", sasl_type);
-                                return Err(Error::ServerError);
-                            }
-                        }
-
-                        SASL_CONTINUE => {
-                            trace!("Continuing SASL");
-
-                            let mut sasl_data = vec![0u8; (len - 8) as usize];
-
-                            match stream.read_exact(&mut sasl_data).await {
-                                Ok(_) => (),
-                                Err(_) => return Err(Error::SocketError),
-                            };
-
-                            let msg = BytesMut::from(&sasl_data[..]);
-                            let sasl_response = scram.update(&msg)?;
-
-                            // SASLResponse
-                            let mut res = BytesMut::new();
-                            res.put_u8(b'p');
-                            res.put_i32(4 + sasl_response.len() as i32);
-                            res.put(sasl_response);
-
-                            write_all(&mut stream, res).await?;
-                        }
-
-                        SASL_FINAL => {
-                            trace!("Final SASL");
-
-                            let mut sasl_final = vec![0u8; len as usize - 8];
-                            match stream.read_exact(&mut sasl_final).await {
-                                Ok(_) => (),
-                                Err(_) => return Err(Error::SocketError),
-                            };
-
-                            match scram.finish(&BytesMut::from(&sasl_final[..])) {
-                                Ok(_) => {
-                                    debug!("SASL authentication successful");
-                                }
-
-                                Err(err) => {
-                                    debug!("SASL authentication failed");
-                                    return Err(err);
-                                }
-                            };
-                        }
-
-                        _ => {
-                            error!("Unsupported authentication mechanism: {}", auth_code);
-                            return Err(Error::ServerError);
-                        }
-                    }
-                }
-
-                // ErrorResponse
-                'E' => {
-                    let error_code = match stream.read_u8().await {
-                        Ok(error_code) => error_code,
-                        Err(_) => return Err(Error::SocketError),
-                    };
-
-                    trace!("Error: {}", error_code);
-
-                    match error_code {
-                        // No error message is present in the message.
-                        MESSAGE_TERMINATOR => (),
-
-                        // An error message will be present.
-                        _ => {
-                            // Read the error message without the terminating null character.
-                            let mut error = vec![0u8; len as usize - 4 - 1];
-
-                            match stream.read_exact(&mut error).await {
-                                Ok(_) => (),
-                                Err(_) => return Err(Error::SocketError),
-                            };
-
-                            // TODO: the error message contains multiple fields; we can decode them and
-                            // present a prettier message to the user.
-                            // See: https://www.postgresql.org/docs/12/protocol-error-fields.html
-                            error!("Server error: {}", String::from_utf8_lossy(&error));
-                        }
-                    };
-
-                    return Err(Error::ServerError);
-                }
-
-                // ParameterStatus
-                'S' => {
-                    let mut param = vec![0u8; len as usize - 4];
-
-                    match stream.read_exact(&mut param).await {
-                        Ok(_) => (),
-                        Err(_) => return Err(Error::SocketError),
-                    };
-
-                    // Save the parameter so we can pass it to the client later.
-                    // These can be server_encoding, client_encoding, server timezone, Postgres version,
-                    // and many more interesting things we should know about the Postgres server we are talking to.
-                    server_info.put_u8(b'S');
-                    server_info.put_i32(len);
-                    server_info.put_slice(&param[..]);
-                }
-
-                // BackendKeyData
-                'K' => {
-                    // The frontend must save these values if it wishes to be able to issue CancelRequest messages later.
-                    // See: <https://www.postgresql.org/docs/12/protocol-message-formats.html>.
-                    process_id = match stream.read_i32().await {
-                        Ok(id) => id,
-                        Err(_) => return Err(Error::SocketError),
-                    };
-
-                    secret_key = match stream.read_i32().await {
-                        Ok(id) => id,
-                        Err(_) => return Err(Error::SocketError),
-                    };
-                }
-
-                // ReadyForQuery
-                'Z' => {
-                    let mut idle = vec![0u8; len as usize - 4];
-
-                    match stream.read_exact(&mut idle).await {
-                        Ok(_) => (),
-                        Err(_) => return Err(Error::SocketError),
-                    };
-
-                    let (read, write) = stream.into_split();
-
-                    let mut server = Server {
-                        address: address.clone(),
-                        read: BufReader::new(read),
-                        write: write,
-                        buffer: BytesMut::with_capacity(8196),
-                        server_info: server_info,
-                        process_id: process_id,
-                        secret_key: secret_key,
-                        in_transaction: false,
-                        data_available: false,
-                        bad: false,
-                        client_server_map: client_server_map,
-                        connected_at: chrono::offset::Utc::now().naive_utc(),
-                        stats: stats,
-                        application_name: String::new(),
-                        last_activity: SystemTime::now(),
-                    };
-
-                    server.set_name("pgcat").await?;
-
-                    return Ok(server);
-                }
-
-                // We have an unexpected message from the server during this exchange.
-                // Means we implemented the protocol wrong or we're not talking to a Postgres server.
-                _ => {
-                    error!("Unknown code: {}", code);
-                    return Err(Error::ProtocolSyncError);
-                }
-            };
-        }
-    }
-
-    /// Issue a query cancellation request to the server.
-    /// Uses a separate connection that's not part of the connection pool.
-    pub async fn cancel(
-        host: &str,
-        port: u16,
-        process_id: i32,
-        secret_key: i32,
-    ) -> Result<(), Error> {
-        let mut stream = match TcpStream::connect(&format!("{}:{}", host, port)).await {
-            Ok(stream) => stream,
-            Err(err) => {
-                error!("Could not connect to server: {}", err);
-                return Err(Error::SocketError);
-            }
-        };
-
-        debug!("Sending CancelRequest");
-
-        let mut bytes = BytesMut::with_capacity(16);
-        bytes.put_i32(16);
-        bytes.put_i32(CANCEL_REQUEST_CODE);
-        bytes.put_i32(process_id);
-        bytes.put_i32(secret_key);
-
-        Ok(write_all(&mut stream, bytes).await?)
-    }
-
-    /// Send messages to the server from the client.
-    pub async fn send(&mut self, messages: BytesMut) -> Result<(), Error> {
-        self.stats
-            .data_sent(messages.len(), self.process_id, self.address.id);
-
-        match write_all_half(&mut self.write, messages).await {
-            Ok(_) => {
-                // Successfully sent to server
-                self.last_activity = SystemTime::now();
-                Ok(())
-            }
-            Err(err) => {
-                error!("Terminating server because of: {:?}", err);
-                self.bad = true;
-                Err(err)
-            }
-        }
-    }
-
-    /// Receive data from the server in response to a client request.
-    /// This method must be called multiple times while `self.is_data_available()` is true
-    /// in order to receive all data the server has to offer.
-    pub async fn recv(&mut self) -> Result<BytesMut, Error> {
-        loop {
-            let mut message = match read_message(&mut self.read).await {
-                Ok(message) => message,
-                Err(err) => {
-                    error!("Terminating server because of: {:?}", err);
-                    self.bad = true;
-                    return Err(err);
-                }
-            };
-
-            // Buffer the message we'll forward to the client later.
-            self.buffer.put(&message[..]);
-
-            let code = message.get_u8() as char;
-            let _len = message.get_i32();
-
-            trace!("Message: {}", code);
-
-            match code {
-                // ReadyForQuery
-                'Z' => {
-                    let transaction_state = message.get_u8() as char;
-
-                    match transaction_state {
-                        // In transaction.
-                        'T' => {
-                            self.in_transaction = true;
-                        }
-
-                        // Idle, transaction over.
-                        'I' => {
-                            self.in_transaction = false;
-                        }
-
-                        // Some error occurred, the transaction was rolled back.
-                        'E' => {
-                            self.in_transaction = true;
-                        }
-
-                        // Something totally unexpected, this is not a Postgres server we know.
-                        _ => {
-                            self.bad = true;
-                            return Err(Error::ProtocolSyncError);
-                        }
-                    };
-
-                    // There is no more data available from the server.
-                    self.data_available = false;
-
-                    break;
-                }
-
-                // DataRow
-                'D' => {
-                    // More data is available after this message, this is not the end of the reply.
-                    self.data_available = true;
-
-                    // Don't flush yet, the more we buffer, the faster this goes...up to a limit.
-                    if self.buffer.len() >= 8196 {
-                        break;
-                    }
-                }
-
-                // CopyInResponse: copy is starting from client to server.
-                'G' => break,
-
-                // CopyOutResponse: copy is starting from the server to the client.
-                'H' => {
-                    self.data_available = true;
-                    break;
-                }
-
-                // CopyData: we are not buffering this one because there will be many more
-                // and we don't know how big this packet could be, best not to take a risk.
-                'd' => break,
-
-                // CopyDone
-                // Buffer until ReadyForQuery shows up, so don't exit the loop yet.
-                'c' => (),
-
-                // Anything else, e.g. errors, notices, etc.
-                // Keep buffering until ReadyForQuery shows up.
-                _ => (),
-            };
-        }
-
-        let bytes = self.buffer.clone();
-
-        // Keep track of how much data we got from the server for stats.
-        self.stats
-            .data_received(bytes.len(), self.process_id, self.address.id);
-
-        // Clear the buffer for next query.
-        self.buffer.clear();
-
-        // Successfully received data from server
-        self.last_activity = SystemTime::now();
-
-        // Pass the data back to the client.
-        Ok(bytes)
-    }
-
-    /// If the server is still inside a transaction.
-    /// If the client disconnects while the server is in a transaction, we will clean it up.
-    pub fn in_transaction(&self) -> bool {
-        self.in_transaction
-    }
-
-    /// We don't buffer all of server responses, e.g. COPY OUT produces too much data.
-    /// The client is responsible to call `self.recv()` while this method returns true.
-    pub fn is_data_available(&self) -> bool {
-        self.data_available
-    }
-
-    /// Server & client are out of sync, we must discard this connection.
-    /// This happens with clients that misbehave.
-    pub fn is_bad(&self) -> bool {
-        self.bad
-    }
-
-    /// Get server startup information to forward it to the client.
-    /// Not used at the moment.
-    pub fn server_info(&self) -> BytesMut {
-        self.server_info.clone()
-    }
-
-    /// Indicate that this server connection cannot be re-used and must be discarded.
-    pub fn mark_bad(&mut self) {
-        error!("Server {:?} marked bad", self.address);
-        self.bad = true;
-    }
-
-    /// Claim this server as mine for the purposes of query cancellation.
-    pub fn claim(&mut self, process_id: i32, secret_key: i32) {
-        let mut guard = self.client_server_map.lock();
-        guard.insert(
-            (process_id, secret_key),
-            (
-                self.process_id,
-                self.secret_key,
-                self.address.host.clone(),
-                self.address.port,
-            ),
-        );
-    }
-
-    /// Execute an arbitrary query against the server.
-    /// It will use the simple query protocol.
-    /// Result will not be returned, so this is useful for things like `SET` or `ROLLBACK`.
-    pub async fn query(&mut self, query: &str) -> Result<(), Error> {
-        let query = simple_query(query);
-
-        self.send(query).await?;
-
-        loop {
-            let _ = self.recv().await?;
-
-            if !self.data_available {
-                break;
-            }
-        }
-
-        Ok(())
-    }
-
-    /// A shorthand for `SET application_name = $1`.
-    #[allow(dead_code)]
-    pub async fn set_name(&mut self, name: &str) -> Result<(), Error> {
-        if self.application_name != name {
-            self.application_name = name.to_string();
-            Ok(self
-                .query(&format!("SET application_name = '{}'", name))
-                .await?)
-        } else {
-            Ok(())
-        }
-    }
-
-    /// Get the servers address.
-    #[allow(dead_code)]
-    pub fn address(&self) -> Address {
-        self.address.clone()
-    }
-
-    /// Get the server's unique identifier.
-    pub fn process_id(&self) -> i32 {
-        self.process_id
-    }
-
-    // Get server's latest response timestamp
-    pub fn last_activity(&self) -> SystemTime {
-        self.last_activity
-    }
-}
-
-impl Drop for Server {
-    /// Try to do a clean shut down. Best effort because
-    /// the socket is in non-blocking mode, so it may not be ready
-    /// for a write.
-    fn drop(&mut self) {
-        self.stats
-            .server_disconnecting(self.process_id(), self.address.id);
-
-        let mut bytes = BytesMut::with_capacity(4);
-        bytes.put_u8(b'X');
-        bytes.put_i32(4);
-
-        match self.write.try_write(&bytes) {
-            Ok(_) => (),
-            Err(_) => debug!("Dirty shutdown"),
-        };
-
-        // Should not matter.
-        self.bad = true;
-
-        let now = chrono::offset::Utc::now().naive_utc();
-        let duration = now - self.connected_at;
-
-        info!(
-            "Server connection closed, session duration: {}",
-            crate::format_duration(&duration)
-        );
-    }
-}
diff --git a/rust_ref/src/sharding.rs b/rust_ref/src/sharding.rs
deleted file mode 100644
index c332c601..00000000
--- a/rust_ref/src/sharding.rs
+++ /dev/null
@@ -1,204 +0,0 @@
-/// Implements various sharding functions.
-use sha1::{Digest, Sha1};
-
-/// See: <https://github.com/postgres/postgres/blob/27b77ecf9f4d5be211900eda54d8155ada50d696/src/include/catalog/partition.h#L20>.
-const PARTITION_HASH_SEED: u64 = 0x7A5B22367996DCFD;
-
-/// The sharding functions we support.
-#[derive(Debug, PartialEq, Copy, Clone)]
-pub enum ShardingFunction {
-    PgBigintHash,
-    Sha1,
-}
-
-/// The sharder.
-pub struct Sharder {
-    /// Number of shards in the cluster.
-    shards: usize,
-
-    /// The sharding function in use.
-    sharding_function: ShardingFunction,
-}
-
-impl Sharder {
-    /// Create new instance of the sharder.
-    pub fn new(shards: usize, sharding_function: ShardingFunction) -> Sharder {
-        Sharder {
-            shards,
-            sharding_function,
-        }
-    }
-
-    /// Compute the shard given sharding key.
-    pub fn shard(&self, key: i64) -> usize {
-        match self.sharding_function {
-            ShardingFunction::PgBigintHash => self.pg_bigint_hash(key),
-            ShardingFunction::Sha1 => self.sha1(key),
-        }
-    }
-
-    /// Hash function used by Postgres to determine which partition
-    /// to put the row in when using HASH(column) partitioning.
-    /// Source: <https://github.com/postgres/postgres/blob/27b77ecf9f4d5be211900eda54d8155ada50d696/src/common/hashfn.c#L631>.
-    /// Supports only 1 bigint at the moment, but we can add more later.
-    fn pg_bigint_hash(&self, key: i64) -> usize {
-        let mut lohalf = key as u32;
-        let hihalf = (key >> 32) as u32;
-        lohalf ^= if key >= 0 { hihalf } else { !hihalf };
-        Self::combine(0, Self::pg_u32_hash(lohalf)) as usize % self.shards
-    }
-
-    /// Example of a hashing function based on SHA1.
-    fn sha1(&self, key: i64) -> usize {
-        let mut hasher = Sha1::new();
-
-        hasher.update(&key.to_string().as_bytes());
-
-        let result = hasher.finalize();
-
-        // Convert the SHA1 hash into hex so we can parse it as a large integer.
-        let hex = format!("{:x}", result);
-
-        // Parse the last 8 bytes as an integer (8 bytes = bigint).
-        let key = i64::from_str_radix(&hex[hex.len() - 8..], 16).unwrap() as usize;
-
-        key % self.shards
-    }
-
-    #[inline]
-    fn rot(x: u32, k: u32) -> u32 {
-        (x << k) | (x >> (32 - k))
-    }
-
-    #[inline]
-    fn mix(mut a: u32, mut b: u32, mut c: u32) -> (u32, u32, u32) {
-        a = a.wrapping_sub(c);
-        a ^= Self::rot(c, 4);
-        c = c.wrapping_add(b);
-
-        b = b.wrapping_sub(a);
-        b ^= Self::rot(a, 6);
-        a = a.wrapping_add(c);
-
-        c = c.wrapping_sub(b);
-        c ^= Self::rot(b, 8);
-        b = b.wrapping_add(a);
-
-        a = a.wrapping_sub(c);
-        a ^= Self::rot(c, 16);
-        c = c.wrapping_add(b);
-
-        b = b.wrapping_sub(a);
-        b ^= Self::rot(a, 19);
-        a = a.wrapping_add(c);
-
-        c = c.wrapping_sub(b);
-        c ^= Self::rot(b, 4);
-        b = b.wrapping_add(a);
-
-        (a, b, c)
-    }
-
-    #[inline]
-    fn _final(mut a: u32, mut b: u32, mut c: u32) -> (u32, u32, u32) {
-        c ^= b;
-        c = c.wrapping_sub(Self::rot(b, 14));
-        a ^= c;
-        a = a.wrapping_sub(Self::rot(c, 11));
-        b ^= a;
-        b = b.wrapping_sub(Self::rot(a, 25));
-        c ^= b;
-        c = c.wrapping_sub(Self::rot(b, 16));
-        a ^= c;
-        a = a.wrapping_sub(Self::rot(c, 4));
-        b ^= a;
-        b = b.wrapping_sub(Self::rot(a, 14));
-        c ^= b;
-        c = c.wrapping_sub(Self::rot(b, 24));
-        (a, b, c)
-    }
-
-    #[inline]
-    fn combine(mut a: u64, b: u64) -> u64 {
-        a ^= b
-            .wrapping_add(0x49a0f4dd15e5a8e3 as u64)
-            .wrapping_add(a << 54)
-            .wrapping_add(a >> 7);
-        a
-    }
-
-    #[inline]
-    fn pg_u32_hash(k: u32) -> u64 {
-        let mut a: u32 = 0x9e3779b9 as u32 + std::mem::size_of::<u32>() as u32 + 3923095 as u32;
-        let mut b = a;
-        let c = a;
-
-        a = a.wrapping_add((PARTITION_HASH_SEED >> 32) as u32);
-        b = b.wrapping_add(PARTITION_HASH_SEED as u32);
-        let (mut a, b, c) = Self::mix(a, b, c);
-
-        a = a.wrapping_add(k);
-
-        let (_a, b, c) = Self::_final(a, b, c);
-
-        ((b as u64) << 32) | (c as u64)
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    // See tests/sharding/partition_hash_test_setup.sql
-    // The output of those SELECT statements will match this test,
-    // confirming that we implemented Postgres BIGINT hashing correctly.
-    #[test]
-    fn test_pg_bigint_hash() {
-        let sharder = Sharder::new(5, ShardingFunction::PgBigintHash);
-
-        let shard_0 = vec![1, 4, 5, 14, 19, 39, 40, 46, 47, 53];
-
-        for v in shard_0 {
-            assert_eq!(sharder.shard(v), 0);
-        }
-
-        let shard_1 = vec![2, 3, 11, 17, 21, 23, 30, 49, 51, 54];
-
-        for v in shard_1 {
-            assert_eq!(sharder.shard(v), 1);
-        }
-
-        let shard_2 = vec![6, 7, 15, 16, 18, 20, 25, 28, 34, 35];
-
-        for v in shard_2 {
-            assert_eq!(sharder.shard(v), 2);
-        }
-
-        let shard_3 = vec![8, 12, 13, 22, 29, 31, 33, 36, 41, 43];
-
-        for v in shard_3 {
-            assert_eq!(sharder.shard(v), 3);
-        }
-
-        let shard_4 = vec![9, 10, 24, 26, 27, 32, 37, 38, 42, 45];
-
-        for v in shard_4 {
-            assert_eq!(sharder.shard(v), 4);
-        }
-    }
-
-    #[test]
-    fn test_sha1_hash() {
-        let sharder = Sharder::new(12, ShardingFunction::Sha1);
-        let ids = vec![
-            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
-        ];
-        let shards = vec![
-            4, 7, 8, 3, 6, 0, 0, 10, 3, 11, 1, 7, 4, 4, 11, 2, 5, 0, 8, 3,
-        ];
-
-        for (i, id) in ids.iter().enumerate() {
-            assert_eq!(sharder.shard(*id), shards[i]);
-        }
-    }
-}
diff --git a/rust_ref/src/stats.rs b/rust_ref/src/stats.rs
deleted file mode 100644
index fde4071b..00000000
--- a/rust_ref/src/stats.rs
+++ /dev/null
@@ -1,564 +0,0 @@
-use arc_swap::ArcSwap;
-/// Statistics and reporting.
-use log::{error, info, trace};
-use once_cell::sync::Lazy;
-use parking_lot::Mutex;
-use std::collections::HashMap;
-use tokio::sync::mpsc::error::TrySendError;
-use tokio::sync::mpsc::{channel, Receiver, Sender};
-
-use crate::pool::get_number_of_addresses;
-
-pub static REPORTER: Lazy<ArcSwap<Reporter>> =
-    Lazy::new(|| ArcSwap::from_pointee(Reporter::default()));
-
-/// Latest stats updated every second; used in SHOW STATS and other admin commands.
-static LATEST_STATS: Lazy<Mutex<HashMap<usize, HashMap<String, i64>>>> =
-    Lazy::new(|| Mutex::new(HashMap::new()));
-
-/// Statistics period used for average calculations.
-/// 15 seconds.
-static STAT_PERIOD: u64 = 15000;
-
-/// The names for the events reported
-/// to the statistics collector.
-#[derive(Debug, Clone, Copy)]
-enum EventName {
-    CheckoutTime,
-    Query,
-    Transaction,
-    DataSent,
-    DataReceived,
-    ClientWaiting,
-    ClientActive,
-    ClientIdle,
-    ClientDisconnecting,
-    ServerActive,
-    ServerIdle,
-    ServerTested,
-    ServerLogin,
-    ServerDisconnecting,
-    UpdateStats,
-    UpdateAverages,
-}
-
-/// Event data sent to the collector
-/// from clients and servers.
-#[derive(Debug, Clone)]
-pub struct Event {
-    /// The name of the event being reported.
-    name: EventName,
-
-    /// The value being reported. Meaning differs based on event name.
-    value: i64,
-
-    /// The client or server connection reporting the event.
-    process_id: i32,
-
-    /// The server the client is connected to.
-    address_id: usize,
-}
-
-/// The statistics reporter. An instance is given
-/// to each possible source of statistics,
-/// e.g. clients, servers, connection pool.
-#[derive(Clone, Debug)]
-pub struct Reporter {
-    tx: Sender<Event>,
-}
-
-impl Default for Reporter {
-    fn default() -> Reporter {
-        let (tx, _rx) = channel(5);
-        Reporter { tx }
-    }
-}
-
-impl Reporter {
-    /// Create a new Reporter instance.
-    pub fn new(tx: Sender<Event>) -> Reporter {
-        Reporter { tx: tx }
-    }
-
-    /// Send statistics to the task keeping track of stats.
-    fn send(&self, event: Event) {
-        let name = event.name;
-        let result = self.tx.try_send(event);
-
-        match result {
-            Ok(_) => trace!(
-                "{:?} event reported successfully, capacity: {}",
-                name,
-                self.tx.capacity()
-            ),
-
-            Err(err) => match err {
-                TrySendError::Full { .. } => error!("{:?} event dropped, buffer full", name),
-                TrySendError::Closed { .. } => error!("{:?} event dropped, channel closed", name),
-            },
-        };
-    }
-
-    /// Report a query executed by a client against
-    /// a server identified by the `address_id`.
-    pub fn query(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::Query,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event);
-    }
-
-    /// Report a transaction executed by a client against
-    /// a server identified by the `address_id`.
-    pub fn transaction(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::Transaction,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Report data sent to a server identified by `address_id`.
-    /// The `amount` is measured in bytes.
-    pub fn data_sent(&self, amount: usize, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::DataSent,
-            value: amount as i64,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Report data received from a server identified by `address_id`.
-    /// The `amount` is measured in bytes.
-    pub fn data_received(&self, amount: usize, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::DataReceived,
-            value: amount as i64,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Time spent waiting to get a healthy connection from the pool
-    /// for a server identified by `address_id`.
-    /// Measured in milliseconds.
-    pub fn checkout_time(&self, ms: u128, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::CheckoutTime,
-            value: ms as i64,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a client identified by `process_id` waiting for a connection
-    /// to a server identified by `address_id`.
-    pub fn client_waiting(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ClientWaiting,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a client identified by `process_id` is done waiting for a connection
-    /// to a server identified by `address_id` and is about to query the server.
-    pub fn client_active(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ClientActive,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a client identified by `process_id` is done querying the server
-    /// identified by `address_id` and is no longer active.
-    pub fn client_idle(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ClientIdle,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a client identified by `process_id` is disconecting from the pooler.
-    /// The last server it was connected to is identified by `address_id`.
-    pub fn client_disconnecting(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ClientDisconnecting,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a server connection identified by `process_id` for
-    /// a configured server identified by `address_id` is actively used
-    /// by a client.
-    pub fn server_active(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ServerActive,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a server connection identified by `process_id` for
-    /// a configured server identified by `address_id` is no longer
-    /// actively used by a client and is now idle.
-    pub fn server_idle(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ServerIdle,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a server connection identified by `process_id` for
-    /// a configured server identified by `address_id` is attempting
-    /// to login.
-    pub fn server_login(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ServerLogin,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a server connection identified by `process_id` for
-    /// a configured server identified by `address_id` is being
-    /// tested before being given to a client.
-    pub fn server_tested(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ServerTested,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-
-    /// Reports a server connection identified by `process_id` is disconecting from the pooler.
-    /// The configured server it was connected to is identified by `address_id`.
-    pub fn server_disconnecting(&self, process_id: i32, address_id: usize) {
-        let event = Event {
-            name: EventName::ServerDisconnecting,
-            value: 1,
-            process_id: process_id,
-            address_id: address_id,
-        };
-
-        self.send(event)
-    }
-}
-
-/// The statistics collector which is receiving statistics
-/// from clients, servers, and the connection pool. There is
-/// only one collector (kind of like a singleton).
-/// The collector can trigger events on its own, e.g.
-/// it updates aggregates every second and averages every
-/// 15 seconds.
-pub struct Collector {
-    rx: Receiver<Event>,
-    tx: Sender<Event>,
-}
-
-impl Collector {
-    /// Create a new collector instance. There should only be one instance
-    /// at a time. This is ensured by mpsc which allows only one receiver.
-    pub fn new(rx: Receiver<Event>, tx: Sender<Event>) -> Collector {
-        Collector { rx, tx }
-    }
-
-    /// The statistics collection handler. It will collect statistics
-    /// for `address_id`s starting at 0 up to `addresses`.
-    pub async fn collect(&mut self) {
-        info!("Events reporter started");
-
-        let stats_template = HashMap::from([
-            ("total_query_count", 0),
-            ("total_query_time", 0),
-            ("total_received", 0),
-            ("total_sent", 0),
-            ("total_xact_count", 0),
-            ("total_xact_time", 0),
-            ("total_wait_time", 0),
-            ("avg_query_count", 0),
-            ("avg_query_time", 0),
-            ("avg_recv", 0),
-            ("avg_sent", 0),
-            ("avg_xact_count", 0),
-            ("avg_xact_time", 0),
-            ("avg_wait_time", 0),
-            ("maxwait_us", 0),
-            ("maxwait", 0),
-            ("cl_waiting", 0),
-            ("cl_active", 0),
-            ("cl_idle", 0),
-            ("sv_idle", 0),
-            ("sv_active", 0),
-            ("sv_login", 0),
-            ("sv_tested", 0),
-        ]);
-
-        let mut stats = HashMap::new();
-
-        // Stats saved after each iteration of the flush event. Used in calculation
-        // of averages in the last flush period.
-        let mut old_stats: HashMap<usize, HashMap<String, i64>> = HashMap::new();
-
-        // Track which state the client and server are at any given time.
-        let mut client_server_states: HashMap<usize, HashMap<i32, EventName>> = HashMap::new();
-
-        // Flush stats to StatsD and calculate averages every 15 seconds.
-        let tx = self.tx.clone();
-        tokio::task::spawn(async move {
-            let mut interval =
-                tokio::time::interval(tokio::time::Duration::from_millis(STAT_PERIOD / 15));
-            loop {
-                interval.tick().await;
-                let address_count = get_number_of_addresses();
-                for address_id in 0..address_count {
-                    let _ = tx.try_send(Event {
-                        name: EventName::UpdateStats,
-                        value: 0,
-                        process_id: -1,
-                        address_id: address_id,
-                    });
-                }
-            }
-        });
-
-        let tx = self.tx.clone();
-        tokio::task::spawn(async move {
-            let mut interval =
-                tokio::time::interval(tokio::time::Duration::from_millis(STAT_PERIOD));
-            loop {
-                interval.tick().await;
-                let address_count = get_number_of_addresses();
-                for address_id in 0..address_count {
-                    let _ = tx.try_send(Event {
-                        name: EventName::UpdateAverages,
-                        value: 0,
-                        process_id: -1,
-                        address_id: address_id,
-                    });
-                }
-            }
-        });
-
-        // The collector loop
-        loop {
-            let stat = match self.rx.recv().await {
-                Some(stat) => stat,
-                None => {
-                    info!("Events collector is shutting down");
-                    return;
-                }
-            };
-
-            let stats = stats
-                .entry(stat.address_id)
-                .or_insert(stats_template.clone());
-            let client_server_states = client_server_states
-                .entry(stat.address_id)
-                .or_insert(HashMap::new());
-            let old_stats = old_stats.entry(stat.address_id).or_insert(HashMap::new());
-
-            // Some are counters, some are gauges...
-            match stat.name {
-                EventName::Query => {
-                    let counter = stats.entry("total_query_count").or_insert(0);
-                    *counter += stat.value;
-                }
-
-                EventName::Transaction => {
-                    let counter = stats.entry("total_xact_count").or_insert(0);
-                    *counter += stat.value;
-                }
-
-                EventName::DataSent => {
-                    let counter = stats.entry("total_sent").or_insert(0);
-                    *counter += stat.value;
-                }
-
-                EventName::DataReceived => {
-                    let counter = stats.entry("total_received").or_insert(0);
-                    *counter += stat.value;
-                }
-
-                EventName::CheckoutTime => {
-                    let counter = stats.entry("total_wait_time").or_insert(0);
-                    *counter += stat.value;
-
-                    let counter = stats.entry("maxwait_us").or_insert(0);
-                    let mic_part = stat.value % 1_000_000;
-
-                    // Report max time here
-                    if mic_part > *counter {
-                        *counter = mic_part;
-                    }
-
-                    let counter = stats.entry("maxwait").or_insert(0);
-                    let seconds = *counter / 1_000_000;
-
-                    if seconds > *counter {
-                        *counter = seconds;
-                    }
-                }
-
-                EventName::ClientActive
-                | EventName::ClientWaiting
-                | EventName::ClientIdle
-                | EventName::ServerActive
-                | EventName::ServerIdle
-                | EventName::ServerTested
-                | EventName::ServerLogin => {
-                    client_server_states.insert(stat.process_id, stat.name);
-                }
-
-                EventName::ClientDisconnecting | EventName::ServerDisconnecting => {
-                    client_server_states.remove(&stat.process_id);
-                }
-
-                EventName::UpdateStats => {
-                    // Calculate connection states
-                    for (_, state) in client_server_states.iter() {
-                        match state {
-                            EventName::ClientActive => {
-                                let counter = stats.entry("cl_active").or_insert(0);
-                                *counter += 1;
-                            }
-
-                            EventName::ClientWaiting => {
-                                let counter = stats.entry("cl_waiting").or_insert(0);
-                                *counter += 1;
-                            }
-
-                            EventName::ServerIdle => {
-                                let counter = stats.entry("sv_idle").or_insert(0);
-                                *counter += 1;
-                            }
-
-                            EventName::ServerActive => {
-                                let counter = stats.entry("sv_active").or_insert(0);
-                                *counter += 1;
-                            }
-
-                            EventName::ServerTested => {
-                                let counter = stats.entry("sv_tested").or_insert(0);
-                                *counter += 1;
-                            }
-
-                            EventName::ServerLogin => {
-                                let counter = stats.entry("sv_login").or_insert(0);
-                                *counter += 1;
-                            }
-
-                            EventName::ClientIdle => {
-                                let counter = stats.entry("cl_idle").or_insert(0);
-                                *counter += 1;
-                            }
-
-                            _ => unreachable!(),
-                        };
-                    }
-
-                    // Update latest stats used in SHOW STATS
-                    let mut guard = LATEST_STATS.lock();
-                    for (key, value) in stats.iter() {
-                        let entry = guard.entry(stat.address_id).or_insert(HashMap::new());
-                        entry.insert(key.to_string(), value.clone());
-                    }
-
-                    // These are re-calculated every iteration of the loop, so we don't want to add values
-                    // from the last iteration.
-                    for stat in &[
-                        "cl_active",
-                        "cl_waiting",
-                        "cl_idle",
-                        "sv_idle",
-                        "sv_active",
-                        "sv_tested",
-                        "sv_login",
-                        "maxwait",
-                        "maxwait_us",
-                    ] {
-                        stats.insert(stat, 0);
-                    }
-                }
-
-                EventName::UpdateAverages => {
-                    // Calculate averages
-                    for stat in &[
-                        "avg_query_count",
-                        "avg_query_time",
-                        "avg_recv",
-                        "avg_sent",
-                        "avg_xact_time",
-                        "avg_xact_count",
-                        "avg_wait_time",
-                    ] {
-                        let total_name = match stat {
-                            &"avg_recv" => "total_received".to_string(), // Because PgBouncer is saving bytes
-                            _ => stat.replace("avg_", "total_"),
-                        };
-
-                        let old_value = old_stats.entry(total_name.clone()).or_insert(0);
-                        let new_value = stats.get(total_name.as_str()).unwrap_or(&0).to_owned();
-                        let avg = (new_value - *old_value) / (STAT_PERIOD as i64 / 1_000); // Avg / second
-
-                        stats.insert(stat, avg);
-                        *old_value = new_value;
-                    }
-                }
-            };
-        }
-    }
-}
-
-/// Get a snapshot of statistics. Updated once a second
-/// by the `Collector`.
-pub fn get_stats() -> HashMap<usize, HashMap<String, i64>> {
-    LATEST_STATS.lock().clone()
-}
-
-/// Get the statistics reporter used to update stats across the pools/clients.
-pub fn get_reporter() -> Reporter {
-    (*(*REPORTER.load())).clone()
-}
diff --git a/rust_ref/src/tls.rs b/rust_ref/src/tls.rs
deleted file mode 100644
index 3bc4a6a0..00000000
--- a/rust_ref/src/tls.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Stream wrapper.
-
-use rustls_pemfile::{certs, rsa_private_keys};
-use std::path::Path;
-use std::sync::Arc;
-use tokio_rustls::rustls::{self, Certificate, PrivateKey};
-use tokio_rustls::TlsAcceptor;
-
-use crate::config::get_config;
-use crate::errors::Error;
-
-// TLS
-pub fn load_certs(path: &Path) -> std::io::Result<Vec<Certificate>> {
-    certs(&mut std::io::BufReader::new(std::fs::File::open(path)?))
-        .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid cert"))
-        .map(|mut certs| certs.drain(..).map(Certificate).collect())
-}
-
-pub fn load_keys(path: &Path) -> std::io::Result<Vec<PrivateKey>> {
-    rsa_private_keys(&mut std::io::BufReader::new(std::fs::File::open(path)?))
-        .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid key"))
-        .map(|mut keys| keys.drain(..).map(PrivateKey).collect())
-}
-
-pub struct Tls {
-    pub acceptor: TlsAcceptor,
-}
-
-impl Tls {
-    pub fn new() -> Result<Self, Error> {
-        let config = get_config();
-
-        let certs = match load_certs(&Path::new(&config.general.tls_certificate.unwrap())) {
-            Ok(certs) => certs,
-            Err(_) => return Err(Error::TlsError),
-        };
-
-        let mut keys = match load_keys(&Path::new(&config.general.tls_private_key.unwrap())) {
-            Ok(keys) => keys,
-            Err(_) => return Err(Error::TlsError),
-        };
-
-        let config = match rustls::ServerConfig::builder()
-            .with_safe_defaults()
-            .with_no_client_auth()
-            .with_single_cert(certs, keys.remove(0))
-            .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))
-        {
-            Ok(c) => c,
-            Err(_) => return Err(Error::TlsError),
-        };
-
-        Ok(Tls {
-            acceptor: TlsAcceptor::from(Arc::new(config)),
-        })
-    }
-}
diff --git a/rust_ref/tests/docker/Dockerfile b/rust_ref/tests/docker/Dockerfile
deleted file mode 100644
index 1f11efb3..00000000
--- a/rust_ref/tests/docker/Dockerfile
+++ /dev/null
@@ -1,5 +0,0 @@
-FROM rust:bullseye
-
-RUN apt-get update && apt-get install llvm-11 psmisc postgresql-contrib postgresql-client ruby ruby-dev libpq-dev python3 python3-pip lcov sudo curl -y
-RUN cargo install cargo-binutils rustfilt
-RUN rustup component add llvm-tools-preview
diff --git a/rust_ref/tests/docker/docker-compose.yml b/rust_ref/tests/docker/docker-compose.yml
deleted file mode 100644
index d86e2399..00000000
--- a/rust_ref/tests/docker/docker-compose.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-version: "3"
-services:
-  pg1:
-    image: postgres:14
-    network_mode: "service:main"
-    environment:
-      POSTGRES_USER: postgres
-      POSTGRES_DB: postgres
-      POSTGRES_PASSWORD: postgres
-      POSTGRES_HOST_AUTH_METHOD: scram-sha-256
-    command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements", "-c", "pg_stat_statements.track=all", "-p", "5432"]
-  pg2:
-    image: postgres:14
-    network_mode: "service:main"
-    environment:
-      POSTGRES_USER: postgres
-      POSTGRES_DB: postgres
-      POSTGRES_PASSWORD: postgres
-      POSTGRES_HOST_AUTH_METHOD: scram-sha-256
-    command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements", "-c", "pg_stat_statements.track=all", "-p", "7432"]
-  pg3:
-    image: postgres:14
-    network_mode: "service:main"
-    environment:
-      POSTGRES_USER: postgres
-      POSTGRES_DB: postgres
-      POSTGRES_PASSWORD: postgres
-      POSTGRES_HOST_AUTH_METHOD: scram-sha-256
-    command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements", "-c", "pg_stat_statements.track=all", "-p", "8432"]
-  pg4:
-    image: postgres:14
-    network_mode: "service:main"
-    environment:
-      POSTGRES_USER: postgres
-      POSTGRES_DB: postgres
-      POSTGRES_PASSWORD: postgres
-      POSTGRES_HOST_AUTH_METHOD: scram-sha-256
-    command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements", "-c", "pg_stat_statements.track=all", "-p", "9432"]
-  main:
-    build: .
-    command: ["bash", "/app/tests/docker/run.sh"]
-    environment:
-      RUSTFLAGS: "-C instrument-coverage"
-      LLVM_PROFILE_FILE: "pgcat-%m.profraw"
-    volumes:
-      - ../../:/app/
-      - /app/target/
diff --git a/rust_ref/tests/docker/run.sh b/rust_ref/tests/docker/run.sh
deleted file mode 100644
index ada5d9ee..00000000
--- a/rust_ref/tests/docker/run.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-rm /app/*.profraw || true
-rm /app/pgcat.profdata || true
-rm -rf /app/cov || true
-
-cd /app/
-
-cargo build
-cargo test --tests
-
-bash .circleci/run_tests.sh
-
-rust-profdata merge -sparse pgcat-*.profraw -o pgcat.profdata
-
-rust-cov export -ignore-filename-regex="rustc|registry" -Xdemangler=rustfilt -instr-profile=pgcat.profdata --object ./target/debug/pgcat --format lcov > ./lcov.info
-
-genhtml lcov.info --output-directory cov --prefix $(pwd)
-
-rm /app/*.profraw
-rm /app/pgcat.profdata
diff --git a/rust_ref/tests/pgbench/simple.sql b/rust_ref/tests/pgbench/simple.sql
deleted file mode 100644
index ad5e6139..00000000
--- a/rust_ref/tests/pgbench/simple.sql
+++ /dev/null
@@ -1,39 +0,0 @@
-
--- \setrandom aid 1 :naccounts
-\set aid random(1, 100000)
--- \setrandom bid 1 :nbranches
-\set bid random(1, 100000)
--- \setrandom tid 1 :ntellers
-\set tid random(1, 100000)
--- \setrandom delta -5000 5000
-\set delta random(-5000,5000)
-
-\set shard random(0, 2)
-
-SET SHARD TO :shard;
-
-SET SERVER ROLE TO 'auto';
-
-BEGIN;
-
-UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
-
-SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
-
-UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
-
-UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
-
-INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
-
-END;
-
-SET SHARDING KEY TO :aid;
-
--- Read load balancing
-SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
-
-SET SERVER ROLE TO 'replica';
-
--- Read load balancing
-SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
diff --git a/rust_ref/tests/python/.gitignore b/rust_ref/tests/python/.gitignore
deleted file mode 100644
index eba74f4c..00000000
--- a/rust_ref/tests/python/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-venv/
\ No newline at end of file
diff --git a/rust_ref/tests/python/requirements.txt b/rust_ref/tests/python/requirements.txt
deleted file mode 100644
index eebd9c90..00000000
--- a/rust_ref/tests/python/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-psycopg2==2.9.3
-psutil==5.9.1
\ No newline at end of file
diff --git a/rust_ref/tests/python/tests.py b/rust_ref/tests/python/tests.py
deleted file mode 100644
index 092fc8cc..00000000
--- a/rust_ref/tests/python/tests.py
+++ /dev/null
@@ -1,252 +0,0 @@
-from typing import Tuple
-import psycopg2
-import psutil
-import os
-import signal
-import time
-
-SHUTDOWN_TIMEOUT = 5
-
-PGCAT_HOST = "127.0.0.1"
-PGCAT_PORT = "6432"
-
-
-def pgcat_start():
-    pg_cat_send_signal(signal.SIGTERM)
-    os.system("./target/debug/pgcat .circleci/pgcat.toml &")
-    time.sleep(2)
-
-
-def pg_cat_send_signal(signal: signal.Signals):
-    for proc in psutil.process_iter(["pid", "name"]):
-        if "pgcat" == proc.name():
-            os.kill(proc.pid, signal)
-    if signal == signal.SIGTERM:
-        # Returns 0 if pgcat process exists
-        time.sleep(2)
-        if not os.system('pgrep pgcat'):
-            raise Exception("pgcat not closed after SIGTERM")
-
-
-def connect_db(
-    autocommit: bool = True,
-    admin: bool = False,
-) -> Tuple[psycopg2.extensions.connection, psycopg2.extensions.cursor]:
-
-    if admin:
-        user = "admin_user"
-        password = "admin_pass"
-        db = "pgcat"
-    else:
-        user = "sharding_user"
-        password = "sharding_user"
-        db = "sharded_db"
-
-    conn = psycopg2.connect(
-        f"postgres://{user}:{password}@{PGCAT_HOST}:{PGCAT_PORT}/{db}?application_name=testing_pgcat",
-        connect_timeout=2,
-    )
-    conn.autocommit = autocommit
-    cur = conn.cursor()
-
-    return (conn, cur)
-
-
-def cleanup_conn(conn: psycopg2.extensions.connection, cur: psycopg2.extensions.cursor):
-    cur.close()
-    conn.close()
-
-
-def test_normal_db_access():
-    conn, cur = connect_db(autocommit=False)
-    cur.execute("SELECT 1")
-    res = cur.fetchall()
-    print(res)
-    cleanup_conn(conn, cur)
-
-
-def test_admin_db_access():
-    conn, cur = connect_db(admin=True)
-
-    cur.execute("SHOW POOLS")
-    res = cur.fetchall()
-    print(res)
-    cleanup_conn(conn, cur)
-
-
-def test_shutdown_logic():
-
-    # - - - - - - - - - - - - - - - - - -
-    # NO ACTIVE QUERIES SIGINT HANDLING
-
-    # Start pgcat
-    pgcat_start()
-
-    # Create client connection and send query (not in transaction)
-    conn, cur = connect_db()
-
-    cur.execute("BEGIN;")
-    cur.execute("SELECT 1;")
-    cur.execute("COMMIT;")
-
-    # Send sigint to pgcat
-    pg_cat_send_signal(signal.SIGINT)
-    time.sleep(1)
-
-    # Check that any new queries fail after sigint since server should close with no active transactions
-    try:
-        cur.execute("SELECT 1;")
-    except psycopg2.OperationalError as e:
-        pass
-    else:
-        # Fail if query execution succeeded
-        raise Exception("Server not closed after sigint")
-
-    cleanup_conn(conn, cur)
-    pg_cat_send_signal(signal.SIGTERM)
-
-    # - - - - - - - - - - - - - - - - - -
-    # HANDLE TRANSACTION WITH SIGINT
-
-    # Start pgcat
-    pgcat_start()
-
-    # Create client connection and begin transaction
-    conn, cur = connect_db()
-
-    cur.execute("BEGIN;")
-    cur.execute("SELECT 1;")
-
-    # Send sigint to pgcat while still in transaction
-    pg_cat_send_signal(signal.SIGINT)
-    time.sleep(1)
-
-    # Check that any new queries succeed after sigint since server should still allow transaction to complete
-    try:
-        cur.execute("SELECT 1;")
-    except psycopg2.OperationalError as e:
-        # Fail if query fails since server closed
-        raise Exception("Server closed while in transaction", e.pgerror)
-
-    cleanup_conn(conn, cur)
-    pg_cat_send_signal(signal.SIGTERM)
-
-    # - - - - - - - - - - - - - - - - - -
-    # NO NEW NON-ADMIN CONNECTIONS DURING SHUTDOWN
-    # Start pgcat
-    pgcat_start()
-
-    # Create client connection and begin transaction
-    transaction_conn, transaction_cur = connect_db()
-
-    transaction_cur.execute("BEGIN;")
-    transaction_cur.execute("SELECT 1;")
-
-    # Send sigint to pgcat while still in transaction
-    pg_cat_send_signal(signal.SIGINT)
-    time.sleep(1)
-
-    start = time.perf_counter()
-    try:
-        conn, cur = connect_db()
-        cur.execute("SELECT 1;")
-        cleanup_conn(conn, cur)
-    except psycopg2.OperationalError as e:
-        time_taken = time.perf_counter() - start
-        if time_taken > 0.1:
-            raise Exception(
-                "Failed to reject connection within 0.1 seconds, got", time_taken, "seconds")
-        pass
-    else:
-        raise Exception("Able connect to database during shutdown")
-
-    cleanup_conn(transaction_conn, transaction_cur)
-    pg_cat_send_signal(signal.SIGTERM)
-
-    # - - - - - - - - - - - - - - - - - -
-    # ALLOW NEW ADMIN CONNECTIONS DURING SHUTDOWN
-    # Start pgcat
-    pgcat_start()
-
-    # Create client connection and begin transaction
-    transaction_conn, transaction_cur = connect_db()
-
-    transaction_cur.execute("BEGIN;")
-    transaction_cur.execute("SELECT 1;")
-
-    # Send sigint to pgcat while still in transaction
-    pg_cat_send_signal(signal.SIGINT)
-    time.sleep(1)
-
-    try:
-        conn, cur = connect_db(admin=True)
-        cur.execute("SHOW DATABASES;")
-        cleanup_conn(conn, cur)
-    except psycopg2.OperationalError as e:
-        raise Exception(e)
-
-    cleanup_conn(transaction_conn, transaction_cur)
-    pg_cat_send_signal(signal.SIGTERM)
-
-    # - - - - - - - - - - - - - - - - - -
-    # ADMIN CONNECTIONS CONTINUING TO WORK AFTER SHUTDOWN
-    # Start pgcat
-    pgcat_start()
-
-    # Create client connection and begin transaction
-    transaction_conn, transaction_cur = connect_db()
-    transaction_cur.execute("BEGIN;")
-    transaction_cur.execute("SELECT 1;")
-
-    admin_conn, admin_cur = connect_db(admin=True)
-    admin_cur.execute("SHOW DATABASES;")
-
-    # Send sigint to pgcat while still in transaction
-    pg_cat_send_signal(signal.SIGINT)
-    time.sleep(1)
-
-    try:
-        admin_cur.execute("SHOW DATABASES;")
-    except psycopg2.OperationalError as e:
-        raise Exception("Could not execute admin command:", e)
-
-    cleanup_conn(transaction_conn, transaction_cur)
-    cleanup_conn(admin_conn, admin_cur)
-    pg_cat_send_signal(signal.SIGTERM)
-
-    # - - - - - - - - - - - - - - - - - -
-    # HANDLE SHUTDOWN TIMEOUT WITH SIGINT
-
-    # Start pgcat
-    pgcat_start()
-
-    # Create client connection and begin transaction, which should prevent server shutdown unless shutdown timeout is reached
-    conn, cur = connect_db()
-
-    cur.execute("BEGIN;")
-    cur.execute("SELECT 1;")
-
-    # Send sigint to pgcat while still in transaction
-    pg_cat_send_signal(signal.SIGINT)
-
-    # pgcat shutdown timeout is set to SHUTDOWN_TIMEOUT seconds, so we sleep for SHUTDOWN_TIMEOUT + 1 seconds
-    time.sleep(SHUTDOWN_TIMEOUT + 1)
-
-    # Check that any new queries succeed after sigint since server should still allow transaction to complete
-    try:
-        cur.execute("SELECT 1;")
-    except psycopg2.OperationalError as e:
-        pass
-    else:
-        # Fail if query execution succeeded
-        raise Exception("Server not closed after sigint and expected timeout")
-
-    cleanup_conn(conn, cur)
-    pg_cat_send_signal(signal.SIGTERM)
-
-    # - - - - - - - - - - - - - - - - - -
-
-
-test_normal_db_access()
-test_admin_db_access()
-test_shutdown_logic()
diff --git a/rust_ref/tests/ruby/.ruby-version b/rust_ref/tests/ruby/.ruby-version
deleted file mode 100644
index cf232b52..00000000
--- a/rust_ref/tests/ruby/.ruby-version
+++ /dev/null
@@ -1,2 +0,0 @@
-3.0.0
-
diff --git a/rust_ref/tests/ruby/Gemfile b/rust_ref/tests/ruby/Gemfile
deleted file mode 100644
index ec7cd3a7..00000000
--- a/rust_ref/tests/ruby/Gemfile
+++ /dev/null
@@ -1,8 +0,0 @@
-source "https://rubygems.org"
-
-gem "pg"
-gem "toml"
-gem "rspec"
-gem "rubocop"
-gem "toxiproxy"
-gem "activerecord"
diff --git a/rust_ref/tests/ruby/Gemfile.lock b/rust_ref/tests/ruby/Gemfile.lock
deleted file mode 100644
index 65d8bce7..00000000
--- a/rust_ref/tests/ruby/Gemfile.lock
+++ /dev/null
@@ -1,74 +0,0 @@
-GEM
-  remote: https://rubygems.org/
-  specs:
-    activemodel (7.0.3.1)
-      activesupport (= 7.0.3.1)
-    activerecord (7.0.3.1)
-      activemodel (= 7.0.3.1)
-      activesupport (= 7.0.3.1)
-    activesupport (7.0.3.1)
-      concurrent-ruby (~> 1.0, >= 1.0.2)
-      i18n (>= 1.6, < 2)
-      minitest (>= 5.1)
-      tzinfo (~> 2.0)
-    ast (2.4.2)
-    concurrent-ruby (1.1.10)
-    diff-lcs (1.5.0)
-    i18n (1.11.0)
-      concurrent-ruby (~> 1.0)
-    minitest (5.16.2)
-    parallel (1.22.1)
-    parser (3.1.2.0)
-      ast (~> 2.4.1)
-    parslet (2.0.0)
-    pg (1.3.2)
-    rainbow (3.1.1)
-    regexp_parser (2.3.1)
-    rexml (3.2.5)
-    rspec (3.11.0)
-      rspec-core (~> 3.11.0)
-      rspec-expectations (~> 3.11.0)
-      rspec-mocks (~> 3.11.0)
-    rspec-core (3.11.0)
-      rspec-support (~> 3.11.0)
-    rspec-expectations (3.11.0)
-      diff-lcs (>= 1.2.0, < 2.0)
-      rspec-support (~> 3.11.0)
-    rspec-mocks (3.11.1)
-      diff-lcs (>= 1.2.0, < 2.0)
-      rspec-support (~> 3.11.0)
-    rspec-support (3.11.0)
-    rubocop (1.29.0)
-      parallel (~> 1.10)
-      parser (>= 3.1.0.0)
-      rainbow (>= 2.2.2, < 4.0)
-      regexp_parser (>= 1.8, < 3.0)
-      rexml (>= 3.2.5, < 4.0)
-      rubocop-ast (>= 1.17.0, < 2.0)
-      ruby-progressbar (~> 1.7)
-      unicode-display_width (>= 1.4.0, < 3.0)
-    rubocop-ast (1.17.0)
-      parser (>= 3.1.1.0)
-    ruby-progressbar (1.11.0)
-    toml (0.3.0)
-      parslet (>= 1.8.0, < 3.0.0)
-    toxiproxy (2.0.1)
-    tzinfo (2.0.4)
-      concurrent-ruby (~> 1.0)
-    unicode-display_width (2.1.0)
-
-PLATFORMS
-  aarch64-linux
-  arm64-darwin-21
-  x86_64-linux
-
-DEPENDENCIES
-  activerecord
-  pg
-  rspec
-  rubocop
-  toml
-  toxiproxy
-
-BUNDLED WITH
-   2.3.21
diff --git a/rust_ref/tests/ruby/helpers/pg_instance.rb b/rust_ref/tests/ruby/helpers/pg_instance.rb
deleted file mode 100644
index 31164575..00000000
--- a/rust_ref/tests/ruby/helpers/pg_instance.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-require 'pg'
-require 'toxiproxy'
-
-class PgInstance
-  attr_reader :port
-  attr_reader :username
-  attr_reader :password
-  attr_reader :database_name
-
-  def initialize(port, username, password, database_name)
-    @original_port = port
-    @toxiproxy_port = 10000 + port.to_i
-    @port = @toxiproxy_port
-
-    @username = username
-    @password = password
-    @database_name = database_name
-    @toxiproxy_name = "database_#{@original_port}"
-    Toxiproxy.populate([{
-      name: @toxiproxy_name,
-      listen: "0.0.0.0:#{@toxiproxy_port}",
-      upstream: "localhost:#{@original_port}",
-    }])
-
-    # Toxiproxy server will outlive our PgInstance objects
-    # so we want to destroy our proxies before exiting
-    # Ruby finalizer is ideal for doing this
-    ObjectSpace.define_finalizer(@toxiproxy_name, proc { Toxiproxy[@toxiproxy_name].destroy })
-  end
-
-  def with_connection
-    conn = PG.connect("postgres://#{@username}:#{@password}@localhost:#{port}/#{database_name}")
-    yield conn
-  ensure
-    conn&.close
-  end
-
-  def reset
-    reset_toxics
-    reset_stats
-  end
-
-  def toxiproxy
-    Toxiproxy[@toxiproxy_name]
-  end
-
-  def take_down
-    if block_given?
-      Toxiproxy[@toxiproxy_name].toxic(:limit_data, bytes: 5).apply { yield }
-    else
-      Toxiproxy[@toxiproxy_name].toxic(:limit_data, bytes: 5).toxics.each(&:save)
-    end
-  end
-
-  def add_latency(latency)
-    if block_given?
-      Toxiproxy[@toxiproxy_name].toxic(:latency, latency: latency).apply { yield }
-    else
-      Toxiproxy[@toxiproxy_name].toxic(:latency, latency: latency).toxics.each(&:save)
-    end
-  end
-
-  def delete_proxy
-    Toxiproxy[@toxiproxy_name].delete
-  end
-
-  def reset_toxics
-    Toxiproxy[@toxiproxy_name].toxics.each(&:destroy)
-  end
-
-  def reset_stats
-    with_connection { |c| c.async_exec("SELECT pg_stat_statements_reset()") }
-  end
-
-  def count_query(query)
-    with_connection { |c| c.async_exec("SELECT SUM(calls) FROM pg_stat_statements WHERE query = '#{query}'")[0]["sum"].to_i }
-  end
-
-  def count_select_1_plus_2
-    with_connection { |c| c.async_exec("SELECT SUM(calls) FROM pg_stat_statements WHERE query = 'SELECT $1 + $2'")[0]["sum"].to_i }
-  end
-end
diff --git a/rust_ref/tests/ruby/helpers/pgcat_helper.rb b/rust_ref/tests/ruby/helpers/pgcat_helper.rb
deleted file mode 100644
index 30b2bc82..00000000
--- a/rust_ref/tests/ruby/helpers/pgcat_helper.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-require 'json'
-require 'ostruct'
-require_relative 'pgcat_process'
-require_relative 'pg_instance'
-
-module Helpers
-  module Pgcat
-    def self.three_shard_setup(pool_name, pool_size)
-      user = {
-        "password" => "sharding_user",
-        "pool_size" => pool_size,
-        "statement_timeout" => 0,
-        "username" => "sharding_user"
-      }
-
-      pgcat    = PgcatProcess.new("info")
-      primary0 = PgInstance.new(5432, user["username"], user["password"], "shard0")
-      primary1 = PgInstance.new(7432, user["username"], user["password"], "shard1")
-      primary2 = PgInstance.new(8432, user["username"], user["password"], "shard2")
-
-      pgcat_cfg = pgcat.current_config
-      pgcat_cfg["pools"] = {
-        "#{pool_name}" => {
-          "default_role" => "any",
-          "pool_mode" => "transaction",
-          "primary_reads_enabled" => false,
-          "query_parser_enabled" => false,
-          "sharding_function" => "pg_bigint_hash",
-          "shards" => {
-            "0" => { "database" => "shard0", "servers" => [["localhost", primary0.port.to_s, "primary"]] },
-            "1" => { "database" => "shard1", "servers" => [["localhost", primary1.port.to_s, "primary"]] },
-            "2" => { "database" => "shard2", "servers" => [["localhost", primary2.port.to_s, "primary"]] },
-          },
-          "users" => { "0" => user }
-        }
-      }
-      pgcat.update_config(pgcat_cfg)
-
-      pgcat.start
-      pgcat.wait_until_ready
-
-      OpenStruct.new.tap do |struct|
-        struct.pgcat = pgcat
-        struct.shards = [primary0, primary1, primary2]
-        struct.all_databases = [primary0, primary1, primary2]
-      end
-    end
-
-    def self.single_shard_setup(pool_name, pool_size)
-      user = {
-        "password" => "sharding_user",
-        "pool_size" => pool_size,
-        "statement_timeout" => 0,
-        "username" => "sharding_user"
-      }
-
-      pgcat = PgcatProcess.new("info")
-      pgcat_cfg = pgcat.current_config
-
-      primary  = PgInstance.new(5432, user["username"], user["password"], "shard0")
-      replica0 = PgInstance.new(7432, user["username"], user["password"], "shard0")
-      replica1 = PgInstance.new(8432, user["username"], user["password"], "shard0")
-      replica2 = PgInstance.new(9432, user["username"], user["password"], "shard0")
-
-      # Main proxy configs
-      pgcat_cfg["pools"] = {
-        "#{pool_name}" => {
-          "default_role" => "any",
-          "pool_mode" => "transaction",
-          "primary_reads_enabled" => false,
-          "query_parser_enabled" => false,
-          "sharding_function" => "pg_bigint_hash",
-          "shards" => {
-            "0" => {
-              "database" => "shard0",
-              "servers" => [
-                ["localhost", primary.port.to_s, "primary"],
-                ["localhost", replica0.port.to_s, "replica"],
-                ["localhost", replica1.port.to_s, "replica"],
-                ["localhost", replica2.port.to_s, "replica"]
-              ]
-            },
-          },
-          "users" => { "0" => user }
-        }
-      }
-      pgcat_cfg["general"]["port"] = pgcat.port
-      pgcat.update_config(pgcat_cfg)
-      pgcat.start
-      pgcat.wait_until_ready
-
-      OpenStruct.new.tap do |struct|
-        struct.pgcat = pgcat
-        struct.primary = primary
-        struct.replicas = [replica0, replica1, replica2]
-        struct.all_databases = [primary, replica0, replica1, replica2]
-      end
-    end
-  end
-end
diff --git a/rust_ref/tests/ruby/helpers/pgcat_process.rb b/rust_ref/tests/ruby/helpers/pgcat_process.rb
deleted file mode 100644
index a5a6d3d3..00000000
--- a/rust_ref/tests/ruby/helpers/pgcat_process.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-require 'pg'
-require 'toml'
-require 'fileutils'
-require 'securerandom'
-
-class PgcatProcess
-  attr_reader :port
-  attr_reader :pid
-
-  def self.finalize(pid, log_filename, config_filename)
-    `kill #{pid}`
-    File.delete(config_filename) if File.exist?(config_filename)
-    File.delete(log_filename) if File.exist?(log_filename)
-  end
-
-  def initialize(log_level)
-    @env = {"RUST_LOG" => log_level}
-    @port = rand(20000..32760)
-    @log_level = log_level
-    @log_filename = "/tmp/pgcat_log_#{SecureRandom.urlsafe_base64}.log"
-    @config_filename = "/tmp/pgcat_cfg_#{SecureRandom.urlsafe_base64}.toml"
-
-    @command = "../../target/debug/pgcat #{@config_filename}"
-
-    FileUtils.cp("../../pgcat.toml", @config_filename)
-    cfg = current_config
-    cfg["general"]["port"] = @port.to_i
-    cfg["general"]["enable_prometheus_exporter"] = false
-
-    update_config(cfg)
-  end
-
-  def logs
-    File.read(@log_filename)
-  end
-
-  def update_config(config_hash)
-    @original_config = current_config
-    output_to_write = TOML::Generator.new(config_hash).body
-    output_to_write = output_to_write.gsub(/,\s*["|'](\d+)["|']\s*,/, ',\1,')
-    File.write(@config_filename, output_to_write)
-  end
-
-  def current_config
-    old_cfg = File.read(@config_filename)
-    loadable_string = old_cfg.gsub(/,\s*(\d+)\s*,/, ', "\1",')
-    TOML.load(loadable_string)
-  end
-
-  def reload_config
-    `kill -s HUP #{@pid}`
-    sleep 0.1
-  end
-
-  def start
-    raise StandardError, "Process is already started" unless @pid.nil?
-    @pid = Process.spawn(@env, @command, err: @log_filename, out: @log_filename)
-    ObjectSpace.define_finalizer(@log_filename, proc { PgcatProcess.finalize(@pid, @log_filename, @config_filename) })
-
-    return self
-  end
-
-  def wait_until_ready
-    exc = nil
-    10.times do
-      PG::connect(example_connection_string).close
-
-      return self
-    rescue => e
-      exc = e
-      sleep(0.5)
-    end
-    puts exc
-    raise StandardError, "Process #{@pid} never became ready. Logs #{logs}"
-  end
-
-  def stop
-    `kill #{@pid}`
-    sleep 0.1
-  end
-
-  def shutdown
-    stop
-    File.delete(@config_filename) if File.exist?(@config_filename)
-    File.delete(@log_filename) if File.exist?(@log_filename)
-  end
-
-  def admin_connection_string
-    cfg = current_config
-    username = cfg["general"]["admin_username"]
-    password = cfg["general"]["admin_password"]
-
-    "postgresql://#{username}:#{password}@0.0.0.0:#{@port}/pgcat"
-  end
-
-  def connection_string(pool_name, username)
-    cfg = current_config
-
-    user_idx, user_obj = cfg["pools"][pool_name]["users"].detect { |k, user| user["username"] == username }
-    password = user_obj["password"]
-
-    "postgresql://#{username}:#{password}@0.0.0.0:#{@port}/#{pool_name}"
-  end
-
-  def example_connection_string
-    cfg = current_config
-    first_pool_name = cfg["pools"].keys[0]
-
-    db_name = first_pool_name
-
-    username = cfg["pools"][first_pool_name]["users"]["0"]["username"]
-    password = cfg["pools"][first_pool_name]["users"]["0"]["password"]
-
-    "postgresql://#{username}:#{password}@0.0.0.0:#{@port}/#{db_name}"
-  end
-end
diff --git a/rust_ref/tests/ruby/load_balancing_spec.rb b/rust_ref/tests/ruby/load_balancing_spec.rb
deleted file mode 100644
index bd98a831..00000000
--- a/rust_ref/tests/ruby/load_balancing_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-require_relative 'spec_helper'
-
-describe "Load Balancing" do
-  let(:processes) { Helpers::Pgcat.single_shard_setup("sharded_db", 5) }
-  after do
-    processes.all_databases.map(&:reset)
-    processes.pgcat.shutdown
-  end
-
-  context "under regular circumstances" do
-    it "balances query volume between all instances" do
-      conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-
-      query_count = QUERY_COUNT
-      expected_share = query_count / processes.all_databases.count
-      failed_count = 0
-
-      query_count.times do
-        conn.async_exec("SELECT 1 + 2")
-      rescue
-        failed_count += 1
-      end
-
-      expect(failed_count).to eq(0)
-      processes.all_databases.map(&:count_select_1_plus_2).each do |instance_share|
-        expect(instance_share).to be_within(expected_share * MARGIN_OF_ERROR).of(expected_share)
-      end
-    end
-  end
-
-  context "when some replicas are down" do
-    it "balances query volume between working instances" do
-      conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-      expected_share = QUERY_COUNT / (processes.all_databases.count - 2)
-      failed_count = 0
-
-      processes[:replicas][0].take_down do
-        processes[:replicas][1].take_down do
-          QUERY_COUNT.times do
-            conn.async_exec("SELECT 1 + 2")
-          rescue
-            conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-            failed_count += 1
-          end
-        end
-      end
-
-      expect(failed_count).to eq(2)
-      processes.all_databases.each do |instance|
-        queries_routed = instance.count_select_1_plus_2
-        if processes.replicas[0..1].include?(instance)
-          expect(queries_routed).to eq(0)
-        else
-          expect(queries_routed).to be_within(expected_share * MARGIN_OF_ERROR).of(expected_share)
-        end
-      end
-    end
-  end
-end
-
diff --git a/rust_ref/tests/ruby/misc_spec.rb b/rust_ref/tests/ruby/misc_spec.rb
deleted file mode 100644
index 9aee49af..00000000
--- a/rust_ref/tests/ruby/misc_spec.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-# frozen_string_literal: true
-require_relative 'spec_helper'
-
-describe "Miscellaneous" do
-  let(:processes) { Helpers::Pgcat.single_shard_setup("sharded_db", 5) }
-  after do
-    processes.all_databases.map(&:reset)
-    processes.pgcat.shutdown
-  end
-
-  describe "Extended Protocol handling" do
-    it "does not send packets that client does not expect during extended protocol sequence" do
-      new_configs = processes.pgcat.current_config
-
-      new_configs["general"]["connect_timeout"] = 500
-      new_configs["general"]["ban_time"] = 1
-      new_configs["general"]["shutdown_timeout"] = 1
-      new_configs["pools"]["sharded_db"]["users"]["0"]["pool_size"] = 1
-
-      processes.pgcat.update_config(new_configs)
-      processes.pgcat.reload_config
-
-      25.times do
-        Thread.new do
-          conn = PG::connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-          conn.async_exec("SELECT pg_sleep(5)") rescue PG::SystemError
-        ensure
-          conn&.close
-        end
-      end
-
-      sleep(0.5)
-      conn_under_test = PG::connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-      stdout, stderr = with_captured_stdout_stderr do
-        15.times do |i|
-          conn_under_test.async_exec("SELECT 1") rescue PG::SystemError
-          conn_under_test.exec_params("SELECT #{i} + $1", [i]) rescue PG::SystemError
-          sleep 1
-        end
-      end
-
-      raise StandardError, "Libpq got unexpected messages while idle" if stderr.include?("arrived from server while idle")
-    end
-  end
-
-  describe "Pool recycling after config reload" do
-    let(:processes) { Helpers::Pgcat.three_shard_setup("sharded_db", 5) }
-
-    it "should update pools for new clients and clients that are no longer in transaction" do
-      server_conn = PG::connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-      server_conn.async_exec("BEGIN")
-
-      # No config change yet, client should set old configs
-      current_datebase_from_pg = server_conn.async_exec("SELECT current_database();")[0]["current_database"]
-      expect(current_datebase_from_pg).to eq('shard0')
-
-      # Swap shards
-      new_config = processes.pgcat.current_config
-      shard0 = new_config["pools"]["sharded_db"]["shards"]["0"]
-      shard1 = new_config["pools"]["sharded_db"]["shards"]["1"]
-      new_config["pools"]["sharded_db"]["shards"]["0"] = shard1
-      new_config["pools"]["sharded_db"]["shards"]["1"] = shard0
-
-      # Reload config
-      processes.pgcat.update_config(new_config)
-      processes.pgcat.reload_config
-      sleep 0.5
-
-      # Config changed but transaction is in progress, client should set old configs
-      current_datebase_from_pg = server_conn.async_exec("SELECT current_database();")[0]["current_database"]
-      expect(current_datebase_from_pg).to eq('shard0')
-      server_conn.async_exec("COMMIT")
-
-      # Transaction finished, client should get new configs
-      current_datebase_from_pg = server_conn.async_exec("SELECT current_database();")[0]["current_database"]
-      expect(current_datebase_from_pg).to eq('shard1')
-
-      # New connection should get new configs
-      server_conn.close()
-      server_conn = PG::connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-      current_datebase_from_pg = server_conn.async_exec("SELECT current_database();")[0]["current_database"]
-      expect(current_datebase_from_pg).to eq('shard1')
-    end
-  end
-
-  describe "Clients closing connection in the middle of transaction" do
-    it "sends a rollback to the server" do
-      conn = PG::connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-      conn.async_exec("SET SERVER ROLE to 'primary'")
-      conn.async_exec("BEGIN")
-      conn.close
-
-      expect(processes.primary.count_query("ROLLBACK")).to eq(1)
-      expect(processes.primary.count_query("DISCARD ALL")).to eq(1)
-    end
-  end
-
-  describe "Server version reporting" do
-    it "reports correct version for normal and admin databases" do
-      server_conn = PG::connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-      expect(server_conn.server_version).not_to eq(0)
-      server_conn.close
-
-      admin_conn = PG::connect(processes.pgcat.admin_connection_string)
-      expect(admin_conn.server_version).not_to eq(0)
-      admin_conn.close
-    end
-  end
-end
diff --git a/rust_ref/tests/ruby/routing_spec.rb b/rust_ref/tests/ruby/routing_spec.rb
deleted file mode 100644
index 24ea137a..00000000
--- a/rust_ref/tests/ruby/routing_spec.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-# frozen_string_literal: true
-require_relative 'spec_helper'
-
-
-describe "Routing" do
-  let(:processes) { Helpers::Pgcat.single_shard_setup("sharded_db", 5) }
-  after do
-    processes.all_databases.map(&:reset)
-    processes.pgcat.shutdown
-  end
-
-  describe "SET ROLE" do
-    context "primary" do
-      it "routes queries only to primary" do
-        conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-        conn.async_exec("SET SERVER ROLE to 'primary'")
-
-        query_count = 30
-        failed_count = 0
-
-        query_count.times do
-          conn.async_exec("SELECT 1 + 2")
-        rescue
-          failed_count += 1
-        end
-
-        expect(failed_count).to eq(0)
-        processes.replicas.map(&:count_select_1_plus_2).each do |instance_share|
-          expect(instance_share).to eq(0)
-        end
-
-        expect(processes.primary.count_select_1_plus_2).to eq(query_count)
-      end
-    end
-    context "replica" do
-      it "routes queries only to replicas" do
-        conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-        conn.async_exec("SET SERVER ROLE to 'replica'")
-
-        expected_share = QUERY_COUNT / processes.replicas.count
-        failed_count = 0
-
-        QUERY_COUNT.times do
-          conn.async_exec("SELECT 1 + 2")
-        rescue
-          failed_count += 1
-        end
-
-        expect(failed_count).to eq(0)
-
-        processes.replicas.map(&:count_select_1_plus_2).each do |instance_share|
-          expect(instance_share).to be_within(expected_share * MARGIN_OF_ERROR).of(expected_share)
-        end
-
-        expect(processes.primary.count_select_1_plus_2).to eq(0)
-      end
-    end
-
-    context "any" do
-      it "routes queries to all instances" do
-        conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
-        conn.async_exec("SET SERVER ROLE to 'any'")
-
-        expected_share = QUERY_COUNT / processes.all_databases.count
-        failed_count = 0
-
-        QUERY_COUNT.times do
-          conn.async_exec("SELECT 1 + 2")
-        rescue
-          failed_count += 1
-        end
-
-        expect(failed_count).to eq(0)
-
-        processes.all_databases.map(&:count_select_1_plus_2).each do |instance_share|
-          expect(instance_share).to be_within(expected_share * MARGIN_OF_ERROR).of(expected_share)
-        end
-      end
-    end
-  end
-end
diff --git a/rust_ref/tests/ruby/spec_helper.rb b/rust_ref/tests/ruby/spec_helper.rb
deleted file mode 100644
index 3050e18a..00000000
--- a/rust_ref/tests/ruby/spec_helper.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-require 'pg'
-require_relative 'helpers/pgcat_helper'
-
-QUERY_COUNT = 300
-MARGIN_OF_ERROR = 0.30
-
-def with_captured_stdout_stderr
-  sout = STDOUT.clone
-  serr = STDERR.clone
-  STDOUT.reopen("/tmp/out.txt", "w+")
-  STDERR.reopen("/tmp/err.txt", "w+")
-  STDOUT.sync = true
-  STDERR.sync = true
-  yield
-  return File.read('/tmp/out.txt'), File.read('/tmp/err.txt')
-ensure
-  STDOUT.reopen(sout)
-  STDERR.reopen(serr)
-end
diff --git a/rust_ref/tests/ruby/tests.rb b/rust_ref/tests/ruby/tests.rb
deleted file mode 100644
index 1c18e15f..00000000
--- a/rust_ref/tests/ruby/tests.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-# frozen_string_literal: true
-require 'pg'
-require 'active_record'
-
-# Uncomment these two to see all queries.
-# ActiveRecord.verbose_query_logs = true
-# ActiveRecord::Base.logger = Logger.new(STDOUT)
-
-ActiveRecord::Base.establish_connection(
-  adapter: 'postgresql',
-  host: '127.0.0.1',
-  port: 6432,
-  username: 'sharding_user',
-  password: 'sharding_user',
-  database: 'sharded_db',
-  application_name: 'testing_pgcat',
-  prepared_statements: false, # Transaction mode
-  advisory_locks: false # Same
-)
-
-class TestSafeTable < ActiveRecord::Base
-  self.table_name = 'test_safe_table'
-end
-
-class ShouldNeverHappenException < RuntimeError
-end
-
-class CreateSafeShardedTable < ActiveRecord::Migration[7.0]
-  # Disable transasctions or things will fly out of order!
-  disable_ddl_transaction!
-
-  SHARDS = 3
-
-  def up
-    SHARDS.times do |x|
-      # This will make this migration reversible!
-      connection.execute "SET SHARD TO '#{x.to_i}'"
-      connection.execute "SET SERVER ROLE TO 'primary'"
-
-      connection.execute <<-SQL
-        CREATE TABLE test_safe_table (
-          id BIGINT PRIMARY KEY,
-          name VARCHAR,
-          description TEXT
-        ) PARTITION BY HASH (id);
-
-        CREATE TABLE test_safe_table_data PARTITION OF test_safe_table
-        FOR VALUES WITH (MODULUS #{SHARDS.to_i}, REMAINDER #{x.to_i});
-      SQL
-    end
-  end
-
-  def down
-    SHARDS.times do |x|
-      connection.execute "SET SHARD TO '#{x.to_i}'"
-      connection.execute "SET SERVER ROLE TO 'primary'"
-      connection.execute 'DROP TABLE test_safe_table CASCADE'
-    end
-  end
-end
-
-SHARDS = 3
-
-2.times do
-  begin
-    CreateSafeShardedTable.migrate(:down)
-  rescue Exception
-    puts "Tables don't exist yet"
-  end
-
-  CreateSafeShardedTable.migrate(:up)
-
-  SHARDS.times do |x|
-    TestSafeTable.connection.execute "SET SHARD TO '#{x.to_i}'"
-    TestSafeTable.connection.execute "SET SERVER ROLE TO 'primary'"
-    TestSafeTable.connection.execute "TRUNCATE #{TestSafeTable.table_name}"
-  end
-
-  # Equivalent to Makara's stick_to_master! except it sticks until it's changed.
-  TestSafeTable.connection.execute "SET SERVER ROLE TO 'primary'"
-
-  200.times do |x|
-    x += 1 # Postgres ids start at 1
-    TestSafeTable.connection.execute "SET SHARDING KEY TO '#{x.to_i}'"
-    TestSafeTable.create(id: x, name: "something_special_#{x.to_i}", description: "It's a surprise!")
-  end
-
-  TestSafeTable.connection.execute "SET SERVER ROLE TO 'replica'"
-
-  100.times do |x|
-    x += 1 # 0 confuses our sharding function
-    TestSafeTable.connection.execute "SET SHARDING KEY TO '#{x.to_i}'"
-    TestSafeTable.find_by_id(x).id
-  end
-
-  # Will use the query parser to direct reads to replicas
-  TestSafeTable.connection.execute "SET SERVER ROLE TO 'auto'"
-
-  100.times do |x|
-    x += 101
-    TestSafeTable.connection.execute "SET SHARDING KEY TO '#{x.to_i}'"
-    TestSafeTable.find_by_id(x).id
-  end
-end
-
-# Test wrong shard
-TestSafeTable.connection.execute "SET SHARD TO '1'"
-begin
-  TestSafeTable.create(id: 5, name: 'test', description: 'test description')
-  raise ShouldNeverHappenException('Uh oh')
-rescue ActiveRecord::StatementInvalid
-  puts 'OK'
-end
diff --git a/rust_ref/tests/sharding/README.md b/rust_ref/tests/sharding/README.md
deleted file mode 100644
index abb908dc..00000000
--- a/rust_ref/tests/sharding/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Sharding tests
-
-This helps us test the sharding algorithm we implemented.
-
-
-## Setup
-
-We setup 3 Postgres DBs, `shard0`, `shard1`, and `shard2`. In each database, we create a partitioned table called `data`. The table is partitioned by hash, and each database will only have _one_ partition, `shard0` will satisfy `modulus 3, remainder 0`, `shard1` will satisfy `modulus 3, remainder 1`, etc.
-
-To set this up, you can just run:
-
-```bash
-psql -f query_routing_setup.sql
-```
-
-## Run the tests
-
-Start up PgCat by running `cargo run --release` in the root of the repo. In a different tab, run this:
-
-```bash
-psql -h 127.0.0.1 -p 6432 -f query_routing_test_insert.sql
-psql -h 127.0.0.1 -p 6432 -f query_routing_test_select.sql
-```
-
-Note that no errors should take place. If our sharding logic was incorrect, we would get some errors
-about unsatisfiable partition bounds. We don't because the pooler picked the correct databases
-given the sharding keys.
-
-Finally, you can validate the result again by running
-
-```bash
-psql -f query_routing_test_validate.sql
-```
-
-## That's it!
\ No newline at end of file
diff --git a/rust_ref/tests/sharding/partition_hash_test_setup.sql b/rust_ref/tests/sharding/partition_hash_test_setup.sql
deleted file mode 100644
index 5e910206..00000000
--- a/rust_ref/tests/sharding/partition_hash_test_setup.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-DROP TABLE IF EXISTS shards CASCADE;
-
-CREATE TABLE shards (
-    id BIGINT,
-    value VARCHAR
-) PARTITION BY HASH (id);
-
--- DROP TABLE IF EXISTS shard_0;
-CREATE TABLE shard_0 PARTITION OF shards FOR VALUES WITH (MODULUS 5, REMAINDER 0);
--- DROP TABLE IF EXISTS shard_1;
-CREATE TABLE shard_1 PARTITION OF shards FOR VALUES WITH (MODULUS 5, REMAINDER 1);
--- DROP TABLE IF EXISTS shard_2;
-CREATE TABLE shard_2 PARTITION OF shards FOR VALUES WITH (MODULUS 5, REMAINDER 2);
--- DROP TABLE IF EXISTS shard_3;
-CREATE TABLE shard_3 PARTITION OF shards FOR VALUES WITH (MODULUS 5, REMAINDER 3);
--- DROP TABLE IF EXISTS shard_4;
-CREATE TABLE shard_4 PARTITION OF shards FOR VALUES WITH (MODULUS 5, REMAINDER 4);
-
-
-INSERT INTO shards SELECT generate_series(1, 500), 'value';
-
-SELECT * FROM shard_0 ORDER BY id LIMIT 10;
-SELECT * FROM shard_1 ORDER BY id LIMIT 10;
-SELECT * FROM shard_2 ORDER BY id LIMIT 10;
-SELECT * FROM shard_3 ORDER BY id LIMIT 10;
-SELECT * FROM shard_4 ORDER BY id LIMIT 10;
diff --git a/rust_ref/tests/sharding/query_routing.sh b/rust_ref/tests/sharding/query_routing.sh
deleted file mode 100644
index d6098fa4..00000000
--- a/rust_ref/tests/sharding/query_routing.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#/bin/bash
-set -e
-
-# Setup all the shards.
-# sudo service postgresql restart
-
-echo "Giving Postgres 5 seconds to start up..."
-
-# sleep 5
-
-# psql -f query_routing_setup.sql
-
-psql -h 127.0.0.1 -p 6432 -f query_routing_test_insert.sql
-
-psql -h 127.0.0.1 -p 6432 -f query_routing_test_select.sql
-
-psql -e -h 127.0.0.1 -p 6432 -f query_routing_test_primary_replica.sql
-
-psql -f query_routing_test_validate.sql
diff --git a/rust_ref/tests/sharding/query_routing_setup.sql b/rust_ref/tests/sharding/query_routing_setup.sql
deleted file mode 100644
index c25ac18e..00000000
--- a/rust_ref/tests/sharding/query_routing_setup.sql
+++ /dev/null
@@ -1,104 +0,0 @@
-DROP DATABASE IF EXISTS shard0;
-DROP DATABASE IF EXISTS shard1;
-DROP DATABASE IF EXISTS shard2;
-DROP DATABASE IF EXISTS some_db;
-
-CREATE DATABASE shard0;
-CREATE DATABASE shard1;
-CREATE DATABASE shard2;
-CREATE DATABASE some_db;
-
-\c shard0
-
-DROP TABLE IF EXISTS data CASCADE;
-
-CREATE TABLE data (
-    id BIGINT,
-    value VARCHAR
-) PARTITION BY HASH (id);
-
-CREATE TABLE data_shard_0 PARTITION OF data FOR VALUES WITH (MODULUS 3, REMAINDER 0);
-
-\c shard1
-
-DROP TABLE IF EXISTS data CASCADE;
-
-CREATE TABLE data (
-    id BIGINT,
-    value VARCHAR
-) PARTITION BY HASH (id);
-
-CREATE TABLE data_shard_1 PARTITION OF data FOR VALUES WITH (MODULUS 3, REMAINDER 1);
-
-
-\c shard2
-
-DROP TABLE IF EXISTS data CASCADE;
-
-CREATE TABLE data (
-    id BIGINT,
-    value VARCHAR
-) PARTITION BY HASH (id);
-
-CREATE TABLE data_shard_2 PARTITION OF data FOR VALUES WITH (MODULUS 3, REMAINDER 2);
-
-
-\c some_db
-
-DROP TABLE IF EXISTS data CASCADE;
-
-CREATE TABLE data (
-    id BIGINT,
-    value VARCHAR
-);
-
-DROP ROLE IF EXISTS sharding_user;
-DROP ROLE IF EXISTS other_user;
-DROP ROLE IF EXISTS simple_user;
-CREATE ROLE sharding_user ENCRYPTED PASSWORD 'sharding_user' LOGIN;
-CREATE ROLE other_user ENCRYPTED PASSWORD 'other_user' LOGIN;
-CREATE ROLE simple_user ENCRYPTED PASSWORD 'simple_user' LOGIN;
-
-GRANT CONNECT ON DATABASE shard0  TO sharding_user;
-GRANT CONNECT ON DATABASE shard1  TO sharding_user;
-GRANT CONNECT ON DATABASE shard2  TO sharding_user;
-
-GRANT CONNECT ON DATABASE shard0  TO other_user;
-GRANT CONNECT ON DATABASE shard1  TO other_user;
-GRANT CONNECT ON DATABASE shard2  TO other_user;
-
-GRANT CONNECT ON DATABASE some_db TO simple_user;
-
-\c shard0
-CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-GRANT EXECUTE ON FUNCTION pg_stat_statements_reset TO sharding_user;
-GRANT ALL ON SCHEMA public TO sharding_user;
-GRANT ALL ON TABLE data TO sharding_user;
-GRANT ALL ON SCHEMA public TO other_user;
-GRANT ALL ON TABLE data TO other_user;
-GRANT EXECUTE ON FUNCTION pg_stat_statements_reset TO other_user;
-
-\c shard1
-CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-GRANT EXECUTE ON FUNCTION pg_stat_statements_reset TO sharding_user;
-GRANT ALL ON SCHEMA public TO sharding_user;
-GRANT ALL ON TABLE data TO sharding_user;
-GRANT ALL ON SCHEMA public TO other_user;
-GRANT ALL ON TABLE data TO other_user;
-GRANT EXECUTE ON FUNCTION pg_stat_statements_reset TO other_user;
-
-
-\c shard2
-CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-GRANT EXECUTE ON FUNCTION pg_stat_statements_reset TO sharding_user;
-GRANT ALL ON SCHEMA public TO sharding_user;
-GRANT ALL ON TABLE data TO sharding_user;
-GRANT ALL ON SCHEMA public TO other_user;
-GRANT ALL ON TABLE data TO other_user;
-GRANT EXECUTE ON FUNCTION pg_stat_statements_reset TO other_user;
-
-\c some_db
-CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-GRANT EXECUTE ON FUNCTION pg_stat_statements_reset TO simple_user;
-GRANT ALL ON SCHEMA public TO simple_user;
-GRANT ALL ON TABLE data TO simple_user;
diff --git a/rust_ref/tests/sharding/query_routing_test_insert.sql b/rust_ref/tests/sharding/query_routing_test_insert.sql
deleted file mode 100644
index ff8a3261..00000000
--- a/rust_ref/tests/sharding/query_routing_test_insert.sql
+++ /dev/null
@@ -1,55 +0,0 @@
-\set ON_ERROR_STOP on
-
-SET SHARDING KEY TO '1';
-INSERT INTO data (id, value) VALUES (1, 'value_1');
-
-SET SHARDING KEY TO '2';
-INSERT INTO data (id, value) VALUES (2, 'value_1');
-
-SET SHARDING KEY TO '3';
-INSERT INTO data (id, value) VALUES (3, 'value_1');
-
-SET SHARDING KEY TO '4';
-INSERT INTO data (id, value) VALUES (4, 'value_1');
-
-SET SHARDING KEY TO '5';
-INSERT INTO data (id, value) VALUES (5, 'value_1');
-
-SET SHARDING KEY TO '6';
-INSERT INTO data (id, value) VALUES (6, 'value_1');
-
-SET SHARDING KEY TO '7';
-INSERT INTO data (id, value) VALUES (7, 'value_1');
-
-SET SHARDING KEY TO '8';
-INSERT INTO data (id, value) VALUES (8, 'value_1');
-
-SET SHARDING KEY TO '9';
-INSERT INTO data (id, value) VALUES (9, 'value_1');
-
-SET SHARDING KEY TO '10';
-INSERT INTO data (id, value) VALUES (10, 'value_1');
-
-SET SHARDING KEY TO '11';
-INSERT INTO data (id, value) VALUES (11, 'value_1');
-
-SET SHARDING KEY TO '12';
-INSERT INTO data (id, value) VALUES (12, 'value_1');
-
-SET SHARDING KEY TO '13';
-INSERT INTO data (id, value) VALUES (13, 'value_1');
-
-SET SHARDING KEY TO '14';
-INSERT INTO data (id, value) VALUES (14, 'value_1');
-
-SET SHARDING KEY TO '15';
-INSERT INTO data (id, value) VALUES (15, 'value_1');
-
-SET SHARDING KEY TO '16';
-INSERT INTO data (id, value) VALUES (16, 'value_1');
-
-set sharding key to '17';
-INSERT INTO data (id, value) VALUES (17, 'value_1');
-
-SeT SHaRDInG KeY to '18';
-INSERT INTO data (id, value) VALUES (18, 'value_1');
diff --git a/rust_ref/tests/sharding/query_routing_test_primary_replica.sql b/rust_ref/tests/sharding/query_routing_test_primary_replica.sql
deleted file mode 100644
index 5fe3cbe3..00000000
--- a/rust_ref/tests/sharding/query_routing_test_primary_replica.sql
+++ /dev/null
@@ -1,162 +0,0 @@
-\set ON_ERROR_STOP on
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '1';
-INSERT INTO data (id, value) VALUES (1, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '1';
-SELECT * FROM data WHERE id = 1;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '2';
-INSERT INTO data (id, value) VALUES (2, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '2';
-SELECT * FROM data WHERE id = 2;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '3';
-INSERT INTO data (id, value) VALUES (3, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '3';
-SELECT * FROM data WHERE id = 3;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '4';
-INSERT INTO data (id, value) VALUES (4, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '4';
-SELECT * FROM data WHERE id = 4;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '5';
-INSERT INTO data (id, value) VALUES (5, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '5';
-SELECT * FROM data WHERE id = 5;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '6';
-INSERT INTO data (id, value) VALUES (6, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '6';
-SELECT * FROM data WHERE id = 6;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '7';
-INSERT INTO data (id, value) VALUES (7, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '7';
-SELECT * FROM data WHERE id = 7;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '8';
-INSERT INTO data (id, value) VALUES (8, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '8';
-SELECT * FROM data WHERE id = 8;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '9';
-INSERT INTO data (id, value) VALUES (9, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '9';
-SELECT * FROM data WHERE id = 9;
-
----
-
-\set ON_ERROR_STOP on
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '10';
-INSERT INTO data (id, value) VALUES (10, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '10';
-SELECT * FROM data WHERE id = 10;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '11';
-INSERT INTO data (id, value) VALUES (11, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '11';
-SELECT * FROM data WHERE id = 11;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '12';
-INSERT INTO data (id, value) VALUES (12, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '12';
-SELECT * FROM data WHERE id = 12;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '13';
-INSERT INTO data (id, value) VALUES (13, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '13';
-SELECT * FROM data WHERE id = 13;
-
----
-
-SET SERVER ROLE TO 'primary';
-SET SHARDING KEY TO '14';
-INSERT INTO data (id, value) VALUES (14, 'value_1');
-
-SET SERVER ROLE TO 'replica';
-SET SHARDING KEY TO '14';
-SELECT * FROM data WHERE id = 14;
-
----
-
-SET SERVER ROLE TO 'primary';
-SELECT 1;
-
-SET SERVER ROLE TO 'replica';
-SELECT 1;
-
-set server role to 'replica';
-SeT SeRver Role TO 'PrImARY';
-select 1;
-
-SET PRIMARY READS TO 'on';
-SELECT 1;
-
-SET PRIMARY READS TO 'off';
-SELECT 1;
-
-SET PRIMARY READS TO 'default';
-SELECT 1;
diff --git a/rust_ref/tests/sharding/query_routing_test_select.sql b/rust_ref/tests/sharding/query_routing_test_select.sql
deleted file mode 100644
index 1b30fdf8..00000000
--- a/rust_ref/tests/sharding/query_routing_test_select.sql
+++ /dev/null
@@ -1,49 +0,0 @@
-\set ON_ERROR_STOP on
-
-SET SHARDING KEY TO '1';
-SELECT * FROM data WHERE id = 1;
-
-SET SHARDING KEY TO '2';
-SELECT * FROM data WHERE id = 2;
-
-SET SHARDING KEY TO '3';
-SELECT * FROM data WHERE id = 3;
-
-SET SHARDING KEY TO '4';
-SELECT * FROM data WHERE id = 4;
-
-SET SHARDING KEY TO '5';
-SELECT * FROM data WHERE id = 5;
-
-SET SHARDING KEY TO '6';
-SELECT * FROM data WHERE id = 6;
-
-SET SHARDING KEY TO '7';
-SELECT * FROM data WHERE id = 7;
-
-SET SHARDING KEY TO '8';
-SELECT * FROM data WHERE id = 8;
-
-SET SHARDING KEY TO '9';
-SELECT * FROM data WHERE id = 9;
-
-SET SHARDING KEY TO '10';
-SELECT * FROM data WHERE id = 10;
-
-SET SHARDING KEY TO '11';
-SELECT * FROM data WHERE id = 11;
-
-SET SHARDING KEY TO '12';
-SELECT * FROM data WHERE id = 12;
-
-SET SHARDING KEY TO '13';
-SELECT * FROM data WHERE id = 13;
-
-SET SHARDING KEY TO '14';
-SELECT * FROM data WHERE id = 14;
-
-SET SHARDING KEY TO '15';
-SELECT * FROM data WHERE id = 15;
-
-SET SHARDING KEY TO '16';
-SELECT * FROM data WHERE id = 16;
diff --git a/rust_ref/tests/sharding/query_routing_test_validate.sql b/rust_ref/tests/sharding/query_routing_test_validate.sql
deleted file mode 100644
index 1647087c..00000000
--- a/rust_ref/tests/sharding/query_routing_test_validate.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-\c shard0
-
-SELECT * FROM data;
-
-\c shard1
-
-SELECT * FROM data;
-
-\c shard2
-
-SELECT * FROM data;
-- 
GitLab