Skip to content

double single-quote ' (used to escape ' in psql) within HERDOC crashes parser #520

@btihen

Description

@btihen

Using

  • Rails 8.0
  • ruby 3.2.2
  • rubycritic 4.9.2

HERDOC that crashes parser:

sql = <<SQL.squish
  insert into public.ruby_scripts
("id","bezeichnung_de","bezeichnung_fr","bezeichnung_it","bezeichnung_en","script","aktiv","cron","lock_version","created_at","updated_at","authorization_roles","referenz")
  select 88,'Datenbasierte Pendenzen generieren','Datenbasierte Pendenzen generieren','Datenbasierte Pendenzen generieren','Datenbasierte Pendenzen generieren',
  'user = User.find_by username: ''admind''
  options[''user_id''] = User.find_by(username: ''admind'').id','1','15 5 * * *',1,'2023-04-14 10:25:01.5092760','2023-04-14 10:35:18.8235140','["admin"]','datenbasierte_pendenzen_generieren'
  where not exists(select *
            from public.ruby_scripts rs
            where rs.id = 88);
SQL
    execute(sql)
  end

Note: this part of the HERDOC seems to crash the parser:

  'user = User.find_by username: ''admind''
  options[''user_id''] = User.find_by(username: ''admind'').id'

Error:

running flay smells
...
running flog smells
...
running reek smells
...
Stopped processing SimpleCov as a previous error not related to SimpleCov has been detected
/builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:110:in `rescue in wrap_exceptions': Source 'db/migrate/20230427122344_create_help_table_for_pendenzen.rb' cannot be processed by Reek due to a syntax error in the source file. (Reek::Errors::SyntaxError)
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:103:in `wrap_exceptions'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:93:in `run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:61:in `smells'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers/smells/reek.rb:30:in `add_smells_to'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers/smells/reek.rb:17:in `block in run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/core/analysed_modules_collection.rb:32:in `each'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/core/analysed_modules_collection.rb:32:in `each'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers/smells/reek.rb:16:in `run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers_runner.rb:32:in `block in run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers_runner.rb:29:in `each'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers_runner.rb:29:in `run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/commands/default.rb:24:in `critique'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/commands/default.rb:19:in `execute'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/cli/application.rb:21:in `execute'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/bin/rubycritic:10:in `<top (required)>'
	from .gems/bin/rubycritic:25:in `load'
	from .gems/bin/rubycritic:25:in `<main>'
/builds/garaio-rem/grem/garaio-rem-core/.gems/gems/parser-3.3.7.4/lib/parser/diagnostic/engine.rb:72:in `process': unexpected token tIDENTIFIER (Parser::SyntaxError)
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/parser-3.3.7.4/lib/parser/base.rb:286:in `on_error'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/racc-1.8.1/lib/racc/parser.rb:263:in `_racc_do_parse_c'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/racc-1.8.1/lib/racc/parser.rb:263:in `do_parse'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/parser-3.3.7.4/lib/parser/base.rb:190:in `parse'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/parser-3.3.7.4/lib/parser/base.rb:207:in `parse_with_comments'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/source/source_code.rb:117:in `parse'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/source/source_code.rb:53:in `syntax_tree'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:116:in `syntax_tree'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:120:in `examine_tree'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:94:in `block in run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:104:in `wrap_exceptions'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:93:in `run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/reek-6.4.0/lib/reek/examiner.rb:61:in `smells'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers/smells/reek.rb:30:in `add_smells_to'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers/smells/reek.rb:17:in `block in run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/core/analysed_modules_collection.rb:32:in `each'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/core/analysed_modules_collection.rb:32:in `each'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers/smells/reek.rb:16:in `run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers_runner.rb:32:in `block in run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers_runner.rb:29:in `each'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/analysers_runner.rb:29:in `run'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/commands/default.rb:24:in `critique'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/commands/default.rb:19:in `execute'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/lib/rubycritic/cli/application.rb:21:in `execute'
	from /builds/garaio-rem/grem/garaio-rem-core/.gems/gems/rubycritic-4.9.2/bin/rubycritic:10:in `<top (required)>'
	from .gems/bin/rubycritic:25:in `load'
	from .gems/bin/rubycritic:25:in `<main>'

The error isn't very clear as to the cause, but once identified I was also able to rewrite the code - so there is a work around. So hopefully, if the problem is not worth fixing this issue will help others with the work around

**work around ** - rewrite code without psql escapes then run the string through quoted_script = ActiveRecord::Base.connection.quote(script) and then insert the string into SQL query.

    script = <<~RUBY
      user = User.find_by(username: 'admind')
      options['user_id'] = User.find_by(username: 'admind').id
    RUBY
    quoted_script = ActiveRecord::Base.connection.quote(script)

    sql = <<SQL.squish
  insert into public.ruby_scripts
("id","bezeichnung_de","bezeichnung_fr","bezeichnung_it","bezeichnung_en","script","aktiv","cron","lock_version","created_at","updated_at","authorization_roles","referenz")
  select 88,'Datenbasierte Pendenzen generieren','Datenbasierte Pendenzen generieren','Datenbasierte Pendenzen generieren','Datenbasierte Pendenzen generieren',
  #{quoted_script},'1','15 5 * * *',1,'2023-04-14 10:25:01.5092760','2023-04-14 10:35:18.8235140','["admin"]','datenbasierte_pendenzen_generieren'
  where not exists(select *
            from public.ruby_scripts rs
            where rs.id = 88);
SQL
    execute(sql)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions