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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions