Skip to content

Raw SQL parameter parsing fails when SQL line endings do not match the host platform #130

Description

@misohacik

Library name and version

  • Kros.KORM 7.4.0 (still present on main)

Description

ParamEnumerator extracts parameter names from raw SQL (Query<T>().Sql(...), ExecuteNonQueryAsync(...)) after normalizing line endings with sql.Replace(Environment.NewLine, " "), and treats only space, , and ) as token delimiters. Parameter parsing therefore silently depends on the SQL string's line endings matching the host platform's Environment.NewLine. SQL text with bare LF line endings (e.g. compiled from sources checked out with eol=lf in .gitattributes) is parsed incorrectly on Windows hosts.

Steps To Reproduce

  1. Build an app from sources with LF line endings (*.cs text eol=lf in .gitattributes), so a verbatim SQL string literal contains bare \n.
  2. Run it on Windows (Environment.NewLine == "\r\n").
  3. Execute a query whose parameter is followed by a line break and a TAB-indented (or unindented) continuation line:
    database.Query<Row>().Sql("SELECT * FROM T WHERE Id = @1\n\tAND Date < @2", id, date).ToArray();
  4. See error.

Expected behavior

Parameters @1 and @2 are extracted and bound regardless of the SQL string's line endings; the query executes.

Actual behavior

The extracted parameter name is "@1\n\tAND" — the token runs to the first space, and the final Trim() cannot remove the embedded \n\t. The command's parameter collection does not contain @1 and SQL Server fails with:

Must declare the scalar variable "@1".

Related edge cases:

  • A parameter followed directly by a TAB (... = @1\tAND ...) fails the same way on every platform.
  • The reverse mismatch (CRLF SQL on a Linux host) survives only by accident: the leftover \r ends up at the end of the token and is removed by Trim().
  • The bug is easy to miss in tests: line endings of verbatim string literals follow the checkout, which follows the platform, so they normally match Environment.NewLine. It typically surfaces only when .gitattributes forces line endings (our production case after switching the repository to eol=lf).

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