Skip to content

Commit

Permalink
Support schema-qualified table names when using create_table :temp wi…
Browse files Browse the repository at this point in the history
…th a Sequel::SQL::QualifiedIdentifier (Fixes #2185)

1fd3976 stopped supporting this
due to problems when setting default_schema on PostgreSQL.  However,
just using the inspect version of Sequel::SQL::QualifiedIdentifier
as the table name is not something any user wants.  PostgreSQL does
not support schema-qualified temporary tables, and I'm not sure
if any other databases do, but it's better to issue the query with
a schema qualified table and have it raise an error, as opposed
to having it silently succeed with a bogus name.
  • Loading branch information
jeremyevans committed Jul 11, 2024
1 parent 93987e6 commit b9b75de
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Support schema-qualified table names when using create_table :temp with a Sequel::SQL::QualifiedIdentifier (jeremyevans) (#2185)

* Support MERGE WHEN NOT MATCHED BY SOURCE on PostgreSQL 17+ (jeremyevans)

* Add stdio_logger extension for a minimal logger that Sequel::Database can use (jeremyevans)
Expand Down
2 changes: 1 addition & 1 deletion lib/sequel/adapters/jdbc/derby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def create_table_as_sql(name, sql, options)
# Temporary table creation on Derby uses DECLARE instead of CREATE.
def create_table_prefix_sql(name, options)
if options[:temp]
"DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)}"
"DECLARE GLOBAL TEMPORARY TABLE #{create_table_table_name_sql(name, options)}"
else
super
end
Expand Down
2 changes: 1 addition & 1 deletion lib/sequel/adapters/shared/db2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def create_table_as_sql(name, sql, options)
# http://www.ibm.com/developerworks/data/library/techarticle/dm-0912globaltemptable/
def create_table_prefix_sql(name, options)
if options[:temp]
"DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)}"
"DECLARE GLOBAL TEMPORARY TABLE #{create_table_table_name_sql(name, options)}"
else
super
end
Expand Down
16 changes: 14 additions & 2 deletions lib/sequel/adapters/shared/mssql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,21 @@ def commit_transaction_sql
# a regular and temporary table, with temporary table names starting with
# a #.
def create_table_prefix_sql(name, options)
"CREATE TABLE #{quote_schema_table(options[:temp] ? "##{name}" : name)}"
"CREATE TABLE #{create_table_table_name_sql(name, options)}"
end


# The SQL to use for the table name for a temporary table.
def create_table_temp_table_name_sql(name, _options)
case name
when String, Symbol
"##{name}"
when SQL::Identifier
"##{name.value}"
else
raise Error, "temporary table names must be strings, symbols, or Sequel::SQL::Identifier instances on Microsoft SQL Server"
end
end

# MSSQL doesn't support CREATE TABLE AS, it only supports SELECT INTO.
# Emulating CREATE TABLE AS using SELECT INTO is only possible if a dataset
# is given as the argument, it can't work with a string, so raise an
Expand Down
2 changes: 1 addition & 1 deletion lib/sequel/adapters/shared/postgres.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1429,7 +1429,7 @@ def create_table_prefix_sql(name, options)
'UNLOGGED '
end

"CREATE #{prefix_sql}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{options[:temp] ? quote_identifier(name) : quote_schema_table(name)}"
"CREATE #{prefix_sql}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)}"
end

# SQL for creating a table with PostgreSQL specific options
Expand Down
16 changes: 15 additions & 1 deletion lib/sequel/database/schema_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,21 @@ def create_table_as_sql(name, sql, options)

# SQL fragment for initial part of CREATE TABLE statement
def create_table_prefix_sql(name, options)
"CREATE #{temporary_table_sql if options[:temp]}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{options[:temp] ? quote_identifier(name) : quote_schema_table(name)}"
"CREATE #{temporary_table_sql if options[:temp]}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)}"
end

# The SQL to use for a table name when creating a table.
# Use of the :temp option can result in different SQL,
# because the rules for temp table naming can differ
# between databases, and temp tables should not use the
# default_schema.
def create_table_table_name_sql(name, options)
options[:temp] ? create_table_temp_table_name_sql(name, options) : quote_schema_table(name)
end

# The SQL to use for the table name for a temporary table.
def create_table_temp_table_name_sql(name, _options)
name.is_a?(String) ? quote_identifier(name) : literal(name)
end

# SQL fragment for initial part of CREATE VIEW statement
Expand Down
11 changes: 11 additions & 0 deletions spec/core/schema_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1445,6 +1445,17 @@ def @db.foreign_key_list(table_name)
@db.sqls.must_equal ['CREATE TEMPORARY TABLE test_tmp (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
'CREATE UNIQUE INDEX test_tmp_name_index ON test_tmp (name)']
end

it "should create a schema-qualified temporary table" do
@db.create_table Sequel[:sch][:test_tmp], :temp => true do
primary_key :id, :integer, :null => false
column :name, :text
index :name, :unique => true
end

@db.sqls.must_equal ['CREATE TEMPORARY TABLE sch.test_tmp (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
'CREATE UNIQUE INDEX sch_test_tmp_name_index ON sch.test_tmp (name)']
end
end

describe "Database#alter_table" do
Expand Down
27 changes: 23 additions & 4 deletions spec/integration/schema_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -384,13 +384,32 @@
end if DB.supports_foreign_key_parsing?

describe "Database" do
after do
before do
DB.drop_table(:items_temp) rescue nil
end

it "should create temporary tables without raising an exception" do
after(:all) do
DB.disconnect
DB.create_table!(:items_temp, :temp=>true){Integer :number}
end

it "should allow creation and use of temporary tables" do
DB.synchronize do
DB.create_table!(:items_temp, :temp=>true){Integer :number}
table = case DB.database_type
when :mssql
Sequel.lit("#items_temp")
when :derby
Sequel[:session][:items_temp]
else
:items_temp
end
DB.from(table).all.must_equal []
end
end

it "should raise when trying to create a schema qualified temporary table" do
proc do
DB.create_table(Sequel[:invalid_temp_schema][:items_temp], :temp=>true){Integer :number}
end.must_raise(DB.database_type == :mssql ? Sequel::Error : Sequel::DatabaseError)
end
end

Expand Down

0 comments on commit b9b75de

Please sign in to comment.