Permalink
Browse files

Use squiggly heredoc to strip odd indentation in the executed SQL

Before:

```
LOG:  execute <unnamed>:             SELECT t.oid, t.typname
                    FROM pg_type as t
                    WHERE t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'bool')

LOG:  execute <unnamed>:               SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
                      FROM pg_type as t
                      LEFT JOIN pg_range as r ON oid = rngtypid
                      WHERE
                        t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'text', 'varchar', 'char', 'name', 'bpchar', 'bool', 'bit', 'varbit', 'timestamptz', 'date', 'money', 'bytea', 'point', 'hstore', 'json', 'jsonb', 'cidr', 'inet', 'uuid', 'xml', 'tsvector', 'macaddr', 'citext', 'ltree', 'interval', 'path', 'line', 'polygon', 'circle', 'lseg', 'box', 'time', 'timestamp', 'numeric')
                        OR t.typtype IN ('r', 'e', 'd')
                        OR t.typinput::varchar = 'array_in'
                        OR t.typelem != 0

LOG:  statement: SHOW TIME ZONE
LOG:  statement: SELECT 1
LOG:  execute <unnamed>:               SELECT COUNT(*)
                      FROM pg_class c
                      LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
                      WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
                      AND c.relname = 'accounts'
                      AND n.nspname = ANY (current_schemas(false))
```

After:

```
LOG:  execute <unnamed>: SELECT t.oid, t.typname
        FROM pg_type as t
        WHERE t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'bool')

LOG:  execute <unnamed>: SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
        FROM pg_type as t
        LEFT JOIN pg_range as r ON oid = rngtypid
                      WHERE
                        t.typname IN ('int2', 'int4', 'int8', 'oid', 'float4', 'float8', 'text', 'varchar', 'char', 'name', 'bpchar', 'bool', 'bit', 'varbit', 'timestamptz', 'date', 'money', 'bytea', 'point', 'hstore', 'json', 'jsonb', 'cidr', 'inet', 'uuid', 'xml', 'tsvector', 'macaddr', 'citext', 'ltree', 'interval', 'path', 'line', 'polygon', 'circle', 'lseg', 'box', 'time', 'timestamp', 'numeric')
                        OR t.typtype IN ('r', 'e', 'd')
                        OR t.typinput::varchar = 'array_in'
                        OR t.typelem != 0

LOG:  statement: SHOW TIME ZONE
LOG:  statement: SELECT 1
LOG:  execute <unnamed>: SELECT COUNT(*)
        FROM pg_class c
        LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
        WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
        AND c.relname = 'accounts'
        AND n.nspname = ANY (current_schemas(false))
```
  • Loading branch information...
kamipo committed Nov 5, 2018
1 parent 6d854f9 commit 1b68ead8f8cb0d7a1771ab82ab20bd79857b40ee
@@ -36,7 +36,7 @@ def run(records)
def query_conditions_for_initial_load
known_type_names = @store.keys.map { |n| "'#{n}'" }
known_type_types = %w('r' 'e' 'd')
<<-SQL % [known_type_names.join(", "), known_type_types.join(", ")]
<<~SQL % [known_type_names.join(", "), known_type_types.join(", ")]
WHERE
t.typname IN (%s)
OR t.typtype IN (%s)
@@ -68,7 +68,7 @@ def index_name_exists?(table_name, index_name)
table = quoted_scope(table_name)
index = quoted_scope(index_name)
query_value(<<-SQL, "SCHEMA").to_i > 0
query_value(<<~SQL, "SCHEMA").to_i > 0
SELECT COUNT(*)
FROM pg_class t
INNER JOIN pg_index d ON t.oid = d.indrelid
@@ -85,7 +85,7 @@ def index_name_exists?(table_name, index_name)
def indexes(table_name) # :nodoc:
scope = quoted_scope(table_name)
result = query(<<-SQL, "SCHEMA")
result = query(<<~SQL, "SCHEMA")
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
pg_catalog.obj_description(i.oid, 'pg_class') AS comment
FROM pg_class t
@@ -196,7 +196,7 @@ def ctype
# Returns an array of schema names.
def schema_names
query_values(<<-SQL, "SCHEMA")
query_values(<<~SQL, "SCHEMA")
SELECT nspname
FROM pg_namespace
WHERE nspname !~ '^pg_.*'
@@ -302,7 +302,7 @@ def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
def pk_and_sequence_for(table) #:nodoc:
# First try looking for a sequence with a dependency on the
# given table's primary key.
result = query(<<-end_sql, "SCHEMA")[0]
result = query(<<~SQL, "SCHEMA")[0]
SELECT attr.attname, nsp.nspname, seq.relname
FROM pg_class seq,
pg_attribute attr,
@@ -319,10 +319,10 @@ def pk_and_sequence_for(table) #:nodoc:
AND cons.contype = 'p'
AND dep.classid = 'pg_class'::regclass
AND dep.refobjid = #{quote(quote_table_name(table))}::regclass
end_sql
SQL
if result.nil? || result.empty?
result = query(<<-end_sql, "SCHEMA")[0]
result = query(<<~SQL, "SCHEMA")[0]
SELECT attr.attname, nsp.nspname,
CASE
WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
@@ -339,7 +339,7 @@ def pk_and_sequence_for(table) #:nodoc:
WHERE t.oid = #{quote(quote_table_name(table))}::regclass
AND cons.contype = 'p'
AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
end_sql
SQL
end
pk = result.shift
@@ -590,13 +590,13 @@ def load_additional_types(oids = nil)
initializer = OID::TypeMapInitializer.new(type_map)
if supports_ranges?
query = <<-SQL
query = <<~SQL
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
FROM pg_type as t
LEFT JOIN pg_range as r ON oid = rngtypid
SQL
else
query = <<-SQL
query = <<~SQL
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
FROM pg_type as t
SQL
@@ -776,7 +776,7 @@ def configure_connection
# - format_type includes the column size constraint, e.g. varchar(50)
# - ::regclass is a function that gives the id for a table name
def column_definitions(table_name)
query(<<-end_sql, "SCHEMA")
query(<<~SQL, "SCHEMA")
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
c.collname, col_description(a.attrelid, a.attnum) AS comment
@@ -787,7 +787,7 @@ def column_definitions(table_name)
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
end_sql
SQL
end
def extract_table_ref_from_insert_sql(sql)
@@ -802,7 +802,7 @@ def arel_visitor
def can_perform_case_insensitive_comparison_for?(column)
@case_insensitive_cache ||= {}
@case_insensitive_cache[column.sql_type] ||= begin
sql = <<-end_sql
sql = <<~SQL
SELECT exists(
SELECT * FROM pg_proc
WHERE proname = 'lower'
@@ -814,7 +814,7 @@ def can_perform_case_insensitive_comparison_for?(column)
WHERE proname = 'lower'
AND castsource = #{quote column.sql_type}::regtype
)
end_sql
SQL
execute_and_clear(sql, "SCHEMA", []) do |result|
result.getvalue(0, 0)
end
@@ -840,7 +840,7 @@ def add_pg_decoders
"bool" => PG::TextDecoder::Boolean,
}
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
query = <<-SQL % known_coder_types.join(", ")
query = <<~SQL % known_coder_types.join(", ")
SELECT t.oid, t.typname
FROM pg_type as t
WHERE t.typname IN (%s)
@@ -11,7 +11,7 @@ def indexes(table_name)
# See https://www.sqlite.org/fileformat2.html#intschema
next if row["name"].starts_with?("sqlite_")
index_sql = query_value(<<-SQL, "SCHEMA")
index_sql = query_value(<<~SQL, "SCHEMA")
SELECT sql
FROM sqlite_master
WHERE name = #{quote(row['name'])} AND type = 'index'
@@ -550,7 +550,7 @@ def translate_exception(exception, message)
def table_structure_with_collation(table_name, basic_structure)
collation_hash = {}
sql = <<-SQL
sql = <<~SQL
SELECT sql FROM
(SELECT * FROM sqlite_master UNION ALL
SELECT * FROM sqlite_temp_master)
@@ -23,7 +23,7 @@ def initialize(message = nil)
# t.string :zipcode
# end
#
# execute <<-SQL
# execute <<~SQL
# ALTER TABLE distributors
# ADD CONSTRAINT zipchk
# CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -41,15 +41,15 @@ def initialize(message = nil)
# t.string :zipcode
# end
#
# execute <<-SQL
# execute <<~SQL
# ALTER TABLE distributors
# ADD CONSTRAINT zipchk
# CHECK (char_length(zipcode) = 5) NO INHERIT;
# SQL
# end
#
# def down
# execute <<-SQL
# execute <<~SQL
# ALTER TABLE distributors
# DROP CONSTRAINT zipchk
# SQL
@@ -68,15 +68,15 @@ def initialize(message = nil)
#
# reversible do |dir|
# dir.up do
# execute <<-SQL
# execute <<~SQL
# ALTER TABLE distributors
# ADD CONSTRAINT zipchk
# CHECK (char_length(zipcode) = 5) NO INHERIT;
# SQL
# end
#
# dir.down do
# execute <<-SQL
# execute <<~SQL
# ALTER TABLE distributors
# DROP CONSTRAINT zipchk
# SQL
@@ -15,13 +15,13 @@ def setup
@connection = ActiveRecord::Base.connection
@connection.transaction do
@connection.execute <<-SQL
CREATE TYPE full_address AS
(
city VARCHAR(90),
street VARCHAR(90)
);
SQL
@connection.execute <<~SQL
CREATE TYPE full_address AS
(
city VARCHAR(90),
street VARCHAR(90)
);
SQL
@connection.create_table("postgresql_composites") do |t|
t.column :address, :full_address
end
@@ -230,7 +230,7 @@ def test_set_session_timezone
def test_get_and_release_advisory_lock
lock_id = 5295901941911233559
list_advisory_locks = <<-SQL
list_advisory_locks = <<~SQL
SELECT locktype,
(classid::bigint << 32) | objid::bigint AS lock_id
FROM pg_locks
@@ -13,7 +13,7 @@ class PostgresqlEnum < ActiveRecord::Base
def setup
@connection = ActiveRecord::Base.connection
@connection.transaction do
@connection.execute <<-SQL
@connection.execute <<~SQL
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
SQL
@connection.create_table("postgresql_enums") do |t|
@@ -22,18 +22,18 @@ def setup
enable_extension!("postgres_fdw", @connection)
foreign_db_config = ARTest.connection_config["arunit2"]
@connection.execute <<-SQL
@connection.execute <<~SQL
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (dbname '#{foreign_db_config["database"]}')
SQL
@connection.execute <<-SQL
@connection.execute <<~SQL
CREATE USER MAPPING FOR CURRENT_USER
SERVER foreign_server
SQL
@connection.execute <<-SQL
@connection.execute <<~SQL
CREATE FOREIGN TABLE foreign_professors (
id int,
name character varying NOT NULL
@@ -45,7 +45,7 @@ def setup
def teardown
disable_extension!("postgres_fdw", @connection)
@connection.execute <<-SQL
@connection.execute <<~SQL
DROP SERVER IF EXISTS foreign_server CASCADE
SQL
end
@@ -394,7 +394,7 @@ def round_trip(range, attribute, value)
end
def insert_range(values)
@connection.execute <<-SQL
@connection.execute <<~SQL
INSERT INTO postgresql_ranges (
id,
date_range,
@@ -27,7 +27,7 @@ def teardown
private
def num_indices_named(name)
@connection.execute(<<-SQL).values.length
@connection.execute(<<~SQL).values.length
SELECT 1 FROM "pg_index"
JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid"
WHERE "pg_class"."relname" = '#{name}'
@@ -146,7 +146,7 @@ def test_drop_schema_if_exists
def test_habtm_table_name_with_schema
ActiveRecord::Base.connection.drop_schema "music", if_exists: true
ActiveRecord::Base.connection.create_schema "music"
ActiveRecord::Base.connection.execute <<-SQL
ActiveRecord::Base.connection.execute <<~SQL
CREATE TABLE music.albums (id serial primary key);
CREATE TABLE music.songs (id serial primary key);
CREATE TABLE music.albums_songs (album_id integer, song_id integer);
@@ -198,10 +198,10 @@ class UUID < ActiveRecord::Base
# Create custom PostgreSQL function to generate UUIDs
# to test dumping tables which columns have defaults with custom functions
connection.execute <<-SQL
CREATE OR REPLACE FUNCTION my_uuid_generator() RETURNS uuid
AS $$ SELECT * FROM #{uuid_function} $$
LANGUAGE SQL VOLATILE;
connection.execute <<~SQL
CREATE OR REPLACE FUNCTION my_uuid_generator() RETURNS uuid
AS $$ SELECT * FROM #{uuid_function} $$
LANGUAGE SQL VOLATILE;
SQL
# Create such a table with custom function as default value generator
@@ -55,11 +55,11 @@ def test_column_types
owner = Owner.create!(name: "hello".encode("ascii-8bit"))
owner.reload
select = Owner.columns.map { |c| "typeof(#{c.name})" }.join ", "
result = Owner.connection.exec_query <<-esql
result = Owner.connection.exec_query <<~SQL
SELECT #{select}
FROM #{Owner.table_name}
WHERE #{Owner.primary_key} = #{owner.id}
esql
SQL
assert_not(result.rows.first.include?("blob"), "should not store blobs")
ensure
@@ -160,13 +160,13 @@ def test_exec_query_typecasts_bind_vals
end
def test_quote_binary_column_escapes_it
DualEncoding.connection.execute(<<-eosql)
DualEncoding.connection.execute(<<~SQL)
CREATE TABLE IF NOT EXISTS dual_encodings (
id integer PRIMARY KEY AUTOINCREMENT,
name varchar(255),
data binary
)
eosql
SQL
str = (+"\x80").force_encoding("ASCII-8BIT")
binary = DualEncoding.new name: "いただきます!", data: str
binary.save!
@@ -261,7 +261,7 @@ def test_tables
end
def test_tables_logs_name
sql = <<-SQL
sql = <<~SQL
SELECT name FROM sqlite_master WHERE name <> 'sqlite_sequence' AND type IN ('table')
SQL
assert_logged [[sql.squish, "SCHEMA", []]] do
@@ -271,7 +271,7 @@ def test_tables_logs_name
def test_table_exists_logs_name
with_example_table do
sql = <<-SQL
sql = <<~SQL
SELECT name FROM sqlite_master WHERE name <> 'sqlite_sequence' AND name = 'ex' AND type IN ('table')
SQL
assert_logged [[sql.squish, "SCHEMA", []]] do
@@ -585,7 +585,7 @@ def assert_logged(logs)
end
def with_example_table(definition = nil, table_name = "ex", &block)
definition ||= <<-SQL
definition ||= <<~SQL
id integer PRIMARY KEY AUTOINCREMENT,
number integer
SQL
@@ -449,7 +449,7 @@ def topic.title() "b" end
end
test "custom field attribute predicate" do
object = Company.find_by_sql(<<-SQL).first
object = Company.find_by_sql(<<~SQL).first
SELECT c1.*, c2.type as string_value, c2.rating as int_value
FROM companies c1, companies c2
WHERE c1.firm_id = c2.id
@@ -20,7 +20,7 @@ class Ebook < ActiveRecord::Base
def setup
super
@connection = ActiveRecord::Base.connection
create_view "ebooks'", <<-SQL
create_view "ebooks'", <<~SQL
SELECT id, name, status FROM books WHERE format = 'ebook'
SQL
end
@@ -106,7 +106,7 @@ class Paperback < ActiveRecord::Base; end
setup do
@connection = ActiveRecord::Base.connection
@connection.execute <<-SQL
@connection.execute <<~SQL
CREATE VIEW paperbacks
AS SELECT name, status FROM books WHERE format = 'paperback'
SQL
@@ -169,7 +169,7 @@ class PrintedBook < ActiveRecord::Base
setup do
@connection = ActiveRecord::Base.connection
@connection.execute <<-SQL
@connection.execute <<~SQL
CREATE VIEW printed_books
AS SELECT id, name, status, format FROM books WHERE format = 'paperback'
SQL
Oops, something went wrong.

0 comments on commit 1b68ead

Please sign in to comment.