Skip to content

v5: SUBSTRING with a start of zero or below follows SQLite #2598

Open

Description

@mathiasrw

Decided for v5 (2026-10-15): the default alasql dialect follows SQLite for SUBSTRING / SUBSTR / MID with a start of zero or below. PR #2521 implements MySQL's behaviour; that becomes part of the mysql dialect module in v5, credited to its author.

Five engines, four behaviours. alasql today matches none of them (JavaScript's substr, off by one):

Call on 'abcdef' alasql today Standard, PostgreSQL, SQL Server MySQL, MariaDB (this PR) Oracle SUBSTR SQLite: v5 default
(1, 3) 'abc' 'abc' 'abc' 'abc' 'abc'
(0, 3) 'f' 'ab' '' 'abc' 'ab'
(-1, 3) 'ef' 'a' 'f' 'f' 'f'
(-2) 'def' 'abcdef' 'ef' 'ef' 'ef'
(-2, 1) 'd' '' 'e' 'e' 'e'
(-7, 3) 'abc' '' '' NULL 'ab'

SQLite 3.43 and PostgreSQL 18 were measured. The others are from their documentation.

Two more faults go in the same change:

  • SUBSTRING(12345, 2, 2) throws y.substr is not a function. SQLite gives '23'.
  • SUBSTRING(s FROM 2 FOR 3) does not parse.

It is a breaking change for a start of zero or below. A positive start does not change. #854 (2017) reported the 0 case.

Related: #2521, #854, #2593 (dialect test).

Activity

  1. added this to the Breaking change milestone on Oct 14, 2026
  2. manas24103 commented on Oct 18, 2026

    @manas24103

    Hi @mathiasrw, I’d like to work on this issue as my next contribution.
    So far, I’ve explored the existing implementation in src/55functions.js and found that SUBSTRING, SUBSTR, and MID currently share an implementation that uses JavaScript’s substr() method with start - 1. I added a regression test in test/test042.js for zero and negative starting positions and was able to reproduce the reported issue: SUBSTRING('abcdef', 0, 3) returns 'f' instead of 'ab', and SUBSTRING('abcdef', -1, 3) returns 'ef' instead of 'f'.
    My next steps are to investigate the dialect-specific handling, update the implementation to match SQLite’s behavior while preserving positive-start behavior, and add tests for the other reported cases, including numeric inputs and the SUBSTRING(s FROM 2 FOR 3) syntax. I’ll also verify that the changes don’t interfere with MySQL-specific behavior and run the relevant tests.
    Would it be possible to assign this issue to me? I’d be happy to continue working on it and submit a PR. Thank you!

  3. manas24103 commented on Oct 19, 2026

    @manas24103

    Hi @mathiasrw,

    Here's a quick update on my progress with this issue.

    So far, I have:

    • Investigated the existing SUBSTRING, SUBSTR, and MID implementation in src/55functions.js.
    • Identified that these functions currently share an implementation based on JavaScript's substr() method, using start - 1.
    • Added regression tests in test/test042.js for zero and negative starting positions.
    • Updated the implementation to handle the reported SQLite compatibility cases.
    • Added tests for numeric inputs and additional negative-start edge cases.
    • Built the project and verified that the targeted test suite passes (5 tests passed).

    I'm currently investigating the parser grammar in src/alasqlparser.jison to understand how to support the alternate syntax SUBSTRING(s FROM 2 FOR 3).

    Next, I'll work on completing SQLite-compatible behavior for the remaining edge cases, investigate MySQL-specific behavior, and run the relevant tests to check for regressions.

    I'll share another update once these changes are complete. Thank you!

  4. manas24103 commented on Oct 19, 2026

    @manas24103

    Hi @mathiasrw,

    Just following up on my request to be assigned to this issue.

    I've now implemented the SQLite-compatible SUBSTRING behavior, added support for both comma-separated and standard SQL syntax (SUBSTRING(s FROM start FOR length)), and added regression coverage in test/test042.js. All 6 targeted tests are passing locally.

    I'm also working on verifying the MySQL-specific behavior so that it remains confined to the MySQL dialect, as described in the issue.

    I'd be happy to continue working on this and submit a PR. Could you please let me know if I can take ownership of this issue?

    Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions