Title: [FEATURE] OData push-down: $select strips columns used only in WHERE/ORDER BY, so the client-side filter silently drops all rows · Issue #682 · stackql/stackql · GitHub
Open Graph Title: [FEATURE] OData push-down: $select strips columns used only in WHERE/ORDER BY, so the client-side filter silently drops all rows · Issue #682 · stackql/stackql
X Title: [FEATURE] OData push-down: $select strips columns used only in WHERE/ORDER BY, so the client-side filter silently drops all rows · Issue #682 · stackql/stackql
Description: Summary When a column appears in WHERE (or ORDER BY) but not in the SELECT list, the OData query-option push-down emits $select with only the projected columns and drops the predicate column from the upstream response. Because push-down ...
Open Graph Description: Summary When a column appears in WHERE (or ORDER BY) but not in the SELECT list, the OData query-option push-down emits $select with only the projected columns and drops the predicate column from t...
X Description: Summary When a column appears in WHERE (or ORDER BY) but not in the SELECT list, the OData query-option push-down emits $select with only the projected columns and drops the predicate column from t...
Opengraph URL: https://github.com/stackql/stackql/issues/682
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[FEATURE] OData push-down: $select strips columns used only in WHERE/ORDER BY, so the client-side filter silently drops all rows","articleBody":"## Summary\n\nWhen a column appears in `WHERE` (or `ORDER BY`) but not in the `SELECT` list, the\nOData query-option push-down emits `$select` with only the projected columns and\ndrops the predicate column from the upstream response. Because push-down keeps the\nclient-side `WHERE` authoritative and re-applies it locally, the predicate column is\nnow missing from every row, the filter matches nothing, and the query returns **zero\nrows despite an HTTP 200 carrying matching data**. It fails silently.\n\n## Repro\n\nProvider: `entra_id` (Microsoft Graph), run with `--http.log.enabled`.\n\n~~~sql\nSELECT id, displayName FROM entra_id.users.users\nWHERE userType = 'Member';\n~~~\n\nOutgoing request — `$select` has no `userType`:\n\n~~~\nhttp request url: 'https://graph.microsoft.com/v1.0/users?$filter=userType eq 'Member'\u0026$select=id,displayName', method: 'GET'\n~~~\n\nGraph returns `200` with 3 matching rows (only `id`,`displayName` — no `userType`).\nFinal result set is empty:\n\n~~~\n|----|-------------|\n| id | displayName |\n|----|-------------|\n~~~\n\nThe 3 rows were discarded by the client-side re-filter because `userType` is absent\nfrom the response. Adding the predicate column to the projection confirms the cause\n(returns the 3 rows):\n\n~~~sql\nSELECT id, displayName, userType FROM entra_id.users.users\nWHERE userType = 'Member'; -- $select=id,displayName,userType\n~~~\n\n## Root cause\n\n`internal/stackql/pushdown/pushdown.go`, `buildPushdownIntent`: the projection placed\nin the `PushdownIntent` is taken from the `SELECT` list only\n(`extractProjectionAndCount(sel.SelectExprs)`). The `WHERE`/`ORDER BY` columns are\ncollected separately (for `$filter`/`$orderby`) and never folded into the projection,\nso the `$select` any-sdk renders strips them.\n\nThe wire request itself is valid OData — Graph filters server-side and projects\ncorrectly. The defect is that stackql re-applies `WHERE`/`ORDER BY` **client-side**\nand the fetched rows no longer carry the needed column. That client-side dependency\nis knowledge only stackql has, so the fix belongs here.\n\n## Fix\n\nIn `buildPushdownIntent`, set the intent projection to the union of the SELECT,\npredicate, and order-by columns:\n\n~~~\nprojection = SELECT-cols ∪ WHERE-cols ∪ ORDER BY-cols\n~~~\n\nThis affects only the pushed `$select`; the SQL output projection is unchanged (still\njust the `SELECT` list, so `SELECT id, displayName ... WHERE userType = ...` still\noutputs two columns). Guard: no-op when the projection is empty — `SELECT *` pushes no\n`$select`, so the bug cannot occur there.\n\n## Tests\n\nAdd push-down cases against the no-auth `stackql_native_test.odata.people` mock:\n\n- filter on unprojected column: `SELECT name FROM ... WHERE city = 'NYC'` asserts the\n wire `$select` includes `city` and the result set is non-empty.\n- order-by on unprojected column: `SELECT name FROM ... ORDER BY age` asserts `$select`\n includes `age`.\n\n## Note\n\nWhichever columns get added to `$select` must satisfy the `select` `supportedColumns`\nallowlist. Where `select`/`filter`/`orderBy` share one allowlist (e.g. entra_id) this\nis automatic; a provider with divergent allowlists could otherwise trip the\nall-or-nothing `$select` gate — worth covering in the fix.\n","author":{"url":"https://github.com/jeffreyaven","@type":"Person","name":"jeffreyaven"},"datePublished":"2026-07-05T22:14:43.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/682/stackql/issues/682"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:028a9678-5ee7-efad-ef8c-2c513fbc4eec |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | D018:9E28B:6710BA:8A9166:6A4D6693 |
| html-safe-nonce | 81dec7c4fdee1476113221c6b1de4b341c26ee01b7df183eaaa0b590d429a06a |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJEMDE4OjlFMjhCOjY3MTBCQTo4QTkxNjY6NkE0RDY2OTMiLCJ2aXNpdG9yX2lkIjoiNTMwNzQ0MjYwMzAxMTk1ODQxOSIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | ccb972acb3c00adefa1b6e610f220f3e3da87a1efc40b4c29638ac719ff9d7f9 |
| hovercard-subject-tag | issue:4814632637 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/stackql/stackql/682/issue_layout |
| twitter:image | https://opengraph.githubassets.com/739ea4c290803d4f5cdd0abb522a537ac5b536eff3c849c18212f77e2388061f/stackql/stackql/issues/682 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/739ea4c290803d4f5cdd0abb522a537ac5b536eff3c849c18212f77e2388061f/stackql/stackql/issues/682 |
| og:image:alt | Summary When a column appears in WHERE (or ORDER BY) but not in the SELECT list, the OData query-option push-down emits $select with only the projected columns and drops the predicate column from t... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | jeffreyaven |
| hostname | github.com |
| expected-hostname | github.com |
| None | 7db3950e3f59095e20a9789440c3dd554efc62d434882ead06ae05b5815605b9 |
| turbo-cache-control | no-preview |
| go-import | github.com/stackql/stackql git https://github.com/stackql/stackql.git |
| octolytics-dimension-user_id | 95105302 |
| octolytics-dimension-user_login | stackql |
| octolytics-dimension-repository_id | 443987542 |
| octolytics-dimension-repository_nwo | stackql/stackql |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 443987542 |
| octolytics-dimension-repository_network_root_nwo | stackql/stackql |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | cd8f6a71db61d6012a0cbb134be844fdbe9b8a45 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width