Skip to content

Fix in-batches OR filter precedence - #255

Open
dajiaohuang wants to merge 2 commits into
ankane:masterfrom
dajiaohuang:fix/in-batches-filter-precedence
Open

dajiaohuang wants to merge 2 commits into
ankane:masterfrom
dajiaohuang:fix/in-batches-filter-precedence

Conversation

@dajiaohuang

Copy link
Copy Markdown

Summary

  • Group the configured WHERE predicate before adding each --in-batches range, so OR filters cannot select rows outside the current batch.
  • Add a regression test for an OR predicate spanning one-row batches.

Validation

  • A synthetic probe exercised the production batch query generation with fake metadata and intercepted COPY; it failed against the base implementation and passed with the change.
  • Ruby syntax checks and git diff --check passed.
  • The project test helper opens three PostgreSQL databases. I did not run the database-backed suite or start a database service.

@by-ae by-ae left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran this against local PostgreSQL 17 with rake test, since the PR says the DB-backed suite wasn't run. Three findings:

1. The new test fails, and not because of the fix. test_where_clause_with_or fails on this branch with Command failed. run_command uses Shellwords.split, so the unquoted where id = 1 OR id = 3 reaches pgsync as several arguments and it prints Usage:. The clause needs quoting, the same way test/sync_test.rb does it:

assert_result("\"where id = 1 OR id = 3\" --in-batches --batch-size 1", source, [], expected)

With that change, the test fails on master and passes with this PR's task.rb, so the fix itself works.

2. Regression for where( with no space. The /\A\s*where\s+/i only strips where when whitespace follows it. A clause like "where(id = 1 OR id = 3)" worked on master. Here it becomes WHERE (where(id = 1 OR id = 3)) AND (...), which is a syntax error. I added this as a test: it passes on master and fails here. \b fixes it, and the whole in_batches file passes with it:

where_clause = sql_clause.sub(/\A\s*where\b/i, "")

3. Not new, but worth knowing. A clause with order by ... limit ... (the README shows "where product_id = {1} order by created_at desc limit 10" for groups) fails with --in-batches both on master and here, because the batch range ends up after LIMIT. Out of scope for this PR, but wrapping the filter in parentheses doesn't help that case.

The rest of the suite passes for me except DataSourceTest#test_url, which fails only because my local server wants a password for postgres://localhost/.... That's unrelated.

@dajiaohuang

Copy link
Copy Markdown
Author

Thanks for the review. Addressed the two in-scope findings in 0f20a2c: the OR-filter test now quotes the SQL argument for Shellwords, and the leading-WHERE matcher uses a word boundary with a regression for where(...). Ruby syntax checks and git diff --check passed; a task-local synthetic probe exercised the production sync_data method with fake endpoints and captured the correctly grouped batches, without opening a database. I did not run the database-backed test suite or query CI. The order by ... limit behavior was reported as also failing on master, so I have left it outside this PR.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants