Skip to content

Conversation

ywelsch
Copy link
Contributor

@ywelsch ywelsch commented Sep 27, 2024

We've noticed that repeated calls of CREATE TABLE IF NOT EXISTS for the same table were causing catalog versions to go up (causing rebinds for other queries). As ORMs are frequently using this pattern to ensure that a table / schema exists before inserting data (i.e. packaging the CREATE TABLE IF NOT EXISTS into the same TX as the INSERT statement), this led to rebinds happening all the time.

statement error
DROP VIEW IF EXISTS integers
----
Existing object integers is of type Table, trying to replace with type View
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"trying to replace" feels out of place in a DROP statement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. This was the existing message in DuckSchemaEntry::DropEntry (not changed by this PR), I just added a test for it (to show that what we do now for create matches with what was already happening on drop). Happy to change the message in DuckSchemaEntry::DropEntry too if you're ok with this being in the scope of this PR. What should the message look like in your opinion?

Copy link
Contributor

@Tishj Tishj Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Yea the changes make sense to me, good catch

Probably something like:
Existing object "integers" is of type Table, unable to drop View for the DROP
Unable to create View "integers", an object of type Table by that name already exists for the CREATE

I hope we have enough context to distinguish between the create and the drop

Copy link
Contributor

@Tishj Tishj Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or actually, we probably want to look at Postgres for the error messages

postgres=# drop view if exists integers;
ERROR:  "integers" is not a view
HINT:  Use DROP TABLE to remove a table.
postgres=# create view integers as select 42;
CREATE VIEW
postgres=# create table if not exists integers(a integer);
NOTICE:  relation "integers" already exists, skipping
CREATE TABLE

Hmm... the earlier messages I send are close enough to this, we don't really do the ERROR, NOTICE, HINT stuff anywhere else

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on your feedback above I pushed 8e8a019.

An interesting realization from your Postgres comparison is that create table if not exists does not throw an exception if the existing object is not a table. Instead it ignores the comment. I've taken that same approach now.

For DROP ... IF EXISTS I've amended the error message to be slightly more correct. Doing a full alignment with Postgres error messages is out of scope for this PR though (I gave it a start and found plenty of inconsistencies as these errors can be thrown from multiple places).

@duckdb-draftbot duckdb-draftbot marked this pull request as draft September 27, 2024 11:57
@ywelsch ywelsch marked this pull request as ready for review September 27, 2024 12:02
@ywelsch ywelsch requested a review from Tishj September 27, 2024 12:03
@@ -14,6 +14,15 @@ CREATE TABLE IF NOT EXISTS integers2 AS SELECT 42
statement ok
CREATE TABLE IF NOT EXISTS integers2 AS SELECT 42

# similar to Postgres, treat as NOOP if the entry exists but the type is different
statement ok
CREATE VIEW IF NOT EXISTS integers2 AS SELECT 42
Copy link
Contributor

@Tishj Tishj Sep 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mytherin how do you feel about this?
Postgres has this behavior (minus a warning/notice message):

postgres=# create table if not exists integers(a integer);
NOTICE:  relation "integers" already exists, skipping
CREATE TABLE

I'd say this should fail because a VIEW by this name doesn't exist, which sounds like what the user expects when this passes to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also note that this (not throwing an exception) is the current behavior of DuckDB as well, there are no actual behavioral changes by this PR except for fixing the issue where the version is no longer incremented on these NOOP commands.

@Mytherin Mytherin merged commit 1eac05e into duckdb:main Oct 4, 2024
42 checks passed
@Mytherin
Copy link
Collaborator

Mytherin commented Oct 4, 2024

Thanks!

github-actions bot pushed a commit to duckdb/duckdb-r that referenced this pull request Oct 16, 2024
Avoid schema changes with IF NOT EXISTS (duckdb/duckdb#14143)
add method to check whether julia connection is open (duckdb/duckdb#14195)
github-actions bot added a commit to duckdb/duckdb-r that referenced this pull request Oct 16, 2024
Avoid schema changes with IF NOT EXISTS (duckdb/duckdb#14143)
add method to check whether julia connection is open (duckdb/duckdb#14195)

Co-authored-by: krlmlr <krlmlr@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants