Dolt Workbench now supports PostgreSQL

FEATURE RELEASE
5 min read

We at DoltHub recently launched the Dolt Workbench, a modern, browser-based, open source SQL workbench with version control features when connected to Dolt. It started with support for MySQL-compatible databases, including MySQL, MariaDB, and Dolt. We're actively developing the Dolt Workbench, and are excited to announce it now supports PostgreSQL (Postgres) databases in preparation of DoltgreSQL, Postgres-flavored Dolt. The Dolt Workbench will support Doltgres in the future when it is more stable.

Getting started with Postgres

It's easy to get started with the Dolt Workbench using our Docker image. Simply pull the image and run it:

% docker pull dolthub/dolt-workbench:latest
% docker run -p 9002:9002 -p 3000:3000 dolthub/dolt-workbench:latest

See the Docker Hub README for instructions for connecting to locally installed Postgres databases.

Navigate to http://localhost:3000 and add your connectivity information.

Connectivity

If you successfully connected to your database, you can start using the workbench. View your tables or create a new one, execute SQL queries, use cell buttons to filter or update your tables, upload files, and more. You can read more about the Dolt Workbench features here.

Postgres Database

Dolt Workbench differences between MySQL and Postgres

While the Dolt Workbench functions mostly the same for different SQL flavors, there are a few differences between using MySQL and PostgreSQL databases.

1. Postgres has schemas

A MySQL connection can have multiple databases. Each database has tables and other metadata, like views, triggers, etc. You can switch between databases using a USE [database] statement.

A Postgres connection can have multiple databases, but each database can also have multiple schema. Each schema has tables and other metadata. When you connect to a database, you cannot change databases using SQL and must start a new connection to use another database. You can however change the schema using a SET SEARCH_PATH = '[schema]' statement.

When connecting to a MySQL database from the Dolt Workbench, you can choose a database and switch between databases using the top navigation breadcrumbs. For Postgres you can switch between schemas, but must create a new connection to use another database.

2. File upload duplicate key behavior

As described in this issue, file upload duplicate key behavior for MySQL and Postgres databases works differently. MySQL file upload uses a LOAD DATA statement to import file data into a table. This lets you specify whether you'd like to ignore or replace if a duplicate key is found in the uploaded file.

Postgres file upload uses a COPY FROM statement. It does not let you specify duplicate key behavior and therefore will currently fail if you upload a file that contains a duplicate key. There are workarounds for this where we can import to a temporary table, and then specify on conflict behavior on upsert. If you want this behavior, feel free to send us a pull request or comment on the GitHub issue.

3. Executing schema definitions

You can view schema definitions in the Schemas tab in the left navigation. For MySQL, this will execute SHOW CREATE statements for tables, views, triggers, events, and procedures to show the related definition.

MySQL Schema

Postgres does not have SHOW CREATE statements. There are some system information functions that return similar definitions for views, triggers, and procedures, but there is not one for tables. Other SQL workbenches will generate the CREATE TABLE statement using the information_schema.columns table. We have an issue opened for this here.

Implementation details

We needed to make some changes to the Dolt Workbench to support SQL flavors other than MySQL. The Dolt Workbench is based on the Hosted Dolt Workbench, a workbench for your Hosted Dolt database. Dolt is MySQL flavored and both workbenches were built to optimize for MySQL, but this will change as we continue to build Doltgres.

The Dolt Workbench is a React web app backed by a GraphQL server. This section will go through the changes we made to each in order to support Postgres. You can learn more about the architecture here.

GraphQL server changes

The Dolt Workbench is backed by a GraphQL server, which manages database connections and executes queries against the current database. It utilizes an ORM called TypeORM.

When the Dolt Workbench only supported MySQL, our GraphQL resolvers could execute raw queries to get certain information that wasn't accessible by built-in TypeORM query builder methods. Once Postgres came into the picture, many of these queries would no longer work. So we refactored the GraphQL server to support a query factory class that could be extended for different SQL dialects.

For example, we show a list of tables for each database or schema in the left navigation. Originally, our tableNames resolver looked something like this:

@Query(_returns => [String])
async tableNames(@Args() args: ListTableArgs): Promise<string[]> {
  return this.dss.query(
    async query => {
      const tables = await query("SHOW FULL TABLES WHERE table_type = 'BASE TABLE'");
      return mapTablesToStrings(tables);
    },
    args.databaseName,
  );
}

Postgres does not have a SHOW TABLES statement. In order to get the table list for both MySQL and Postgres, we added a getTableNames method to our new query factory class, which can use different queries for each SQL dialect.

// MySQL query factory
async getTableNames(args: t.DBArgs): Promise<string[]> {
  const res = await this.query(
    "SHOW FULL TABLES WHERE table_type = 'BASE TABLE'",
    [],
    args.databaseName,
  );
  return mapTablesToStrings(res);
}
// Postgres query factory
async getTableNames(args: t.SchemaArgs): Promise<string[]> {
  const res = await this.query(
    "SELECT * FROM pg_catalog.pg_tables where schemaname=$1;",
    [args.schemaName],
    args.schemaName,
  );
  return res.map(r => r.tablename);
}

And now in our resolver, we use this method:

@Query(_returns => [String])
async tableNames(@Args() args: ListTableArgs): Promise<string[]> {
  const conn = this.conn.connection(); // Gets the query factory based on the SQL dialect
  const tables = await conn.getTableNames(args);
  return tables;
}

These changes allow us to more easily add other SQL flavors in the future, so let us know if you have any requests.

React changes

The Dolt Workbench front end is built using Next.js, a React framework for the web. It uses Apollo Client to manage state for both local and remote data for GraphQL. Our GraphQL server handles most of the data fetching differences between MySQL and Postgres, so there weren't many changes we needed to make to our Apollo queries.

However, some workbench features, such as the SQL console and cell buttons that generate queries to insert, update, or remove rows and cells do not utilize the GraphQL server and instead use a library called node-sql-parser. This library helps us parse queries that are executed from the SQL console and build queries for the cell buttons. We only ever used the MySQL dialect, so we had a library of utility functions we could use for these operations.

Now that we are supporting more SQL dialects, we moved these functions to a React hook that can query the GraphQL server for the database type and return the same utility functions based on the type.

We were also building raw query strings for buttons and links that generate queries. For example, when you use the column sort cell button, we generate a SELECT * FROM `[table]` ORDER BY [col] statement. MySQL uses backticks to escape table names, whereas Postgres uses double quotes. All these raw generated query strings would break for Postgres. So we made an additional React hook to build queries using node-sql-parser based on the dialect.

To come

Since the beginning of Dolt, we've had people asking for Postgres. We hear you and want you to know we're taking concrete steps toward making it happen. We're actively developing Doltgres, and the Dolt Workbench will support Doltgres when it is more stable. In the meantime, use the Dolt Workbench with your existing Postgres database.

Want the Dolt Workbench to support other SQL flavors? Let us know on Discord or file a GitHub issue. The changes we made for Postgres will make it easier to support more SQL flavors in the future.

SHARE

JOIN THE DATA EVOLUTION

Get started with Dolt

Or join our mailing list to get product updates.