Skip to content

Commit 1ede45f

Browse files
VJ-yadavVijay Yadav
andcommitted
fix: keep SQL templates self-contained, use .replace() for filter placeholders
Address review feedback on PR #432: 1. Restore GROUP BY, ORDER BY, and LIMIT clauses to SQL template constants so each template is a complete, readable query. Only the optional WHERE filter placeholders ({warehouse_filter}, {user_filter}, etc.) are replaced at the call site via .replace() — safe because they are hardcoded SQL fragments, not user input. 2. Fix incorrect comment in query-history.ts claiming Postgres driver does not support parameterized binds. The actual limitation is that our connector wrapper (packages/drivers/src/postgres.ts) does not yet pass the _binds parameter through to pg. LIMIT is still rendered inline via Math.floor(Number(limit)) until the driver is updated. 3. Double-newline issue from empty filters is resolved by the .replace() approach — replacing an empty placeholder leaves at most a blank line, which SQL ignores. Files: credit-analyzer.ts, query-history.ts, role-access.ts, tags.ts Co-Authored-By: Vijay Yadav <vijay@studentsucceed.com>
1 parent ca0d93c commit 1ede45f

File tree

5 files changed

+45
-17
lines changed

5 files changed

+45
-17
lines changed

packages/opencode/src/altimate/native/finops/credit-analyzer.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ SELECT
2727
AVG(credits_used) as avg_credits_per_query
2828
FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY
2929
WHERE start_time >= DATEADD('day', ?, CURRENT_TIMESTAMP())
30+
{warehouse_filter}
31+
GROUP BY warehouse_name, DATE_TRUNC('day', start_time)
32+
ORDER BY usage_date DESC, credits_used DESC
33+
LIMIT ?
3034
`
3135

3236
const SNOWFLAKE_CREDIT_SUMMARY_SQL = `
@@ -194,8 +198,7 @@ function buildCreditUsageSql(
194198
const whF = warehouseFilter ? (binds.push(warehouseFilter), "AND warehouse_name = ?") : ""
195199
binds.push(limit)
196200
return {
197-
sql: SNOWFLAKE_CREDIT_USAGE_SQL +
198-
`${whF}\nGROUP BY warehouse_name, DATE_TRUNC('day', start_time)\nORDER BY usage_date DESC, credits_used DESC\nLIMIT ?\n`,
201+
sql: SNOWFLAKE_CREDIT_USAGE_SQL.replace("{warehouse_filter}", whF),
199202
binds,
200203
}
201204
}

packages/opencode/src/altimate/native/finops/query-history.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ SELECT
3333
credits_used_cloud_services
3434
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
3535
WHERE start_time >= DATEADD('day', ?, CURRENT_TIMESTAMP())
36+
{user_filter}
37+
{warehouse_filter}
38+
ORDER BY start_time DESC
39+
LIMIT ?
3640
`
3741

3842
const POSTGRES_HISTORY_SQL = `
@@ -55,6 +59,7 @@ SELECT
5559
calls as execution_count
5660
FROM pg_stat_statements
5761
ORDER BY total_exec_time DESC
62+
LIMIT {limit}
5863
`
5964

6065
const BIGQUERY_HISTORY_SQL = `
@@ -122,14 +127,20 @@ function buildHistoryQuery(
122127
const whF = warehouseFilter ? (binds.push(warehouseFilter), "AND warehouse_name = ?") : ""
123128
binds.push(limit)
124129
return {
125-
sql: SNOWFLAKE_HISTORY_SQL +
126-
`${userF}\n${whF}\nORDER BY start_time DESC\nLIMIT ?\n`,
130+
sql: SNOWFLAKE_HISTORY_SQL
131+
.replace("{user_filter}", userF)
132+
.replace("{warehouse_filter}", whF),
127133
binds,
128134
}
129135
}
130136
if (whType === "postgres" || whType === "postgresql") {
131-
// Postgres driver does not support parameterized binds — render LIMIT inline
132-
return { sql: POSTGRES_HISTORY_SQL + `LIMIT ${Math.floor(Number(limit))}\n`, binds: [] }
137+
// The Postgres connector (packages/drivers/src/postgres.ts) does not yet
138+
// pass binds through to pg — its execute() ignores the _binds parameter.
139+
// Render LIMIT inline with Math.floor to prevent injection.
140+
return {
141+
sql: POSTGRES_HISTORY_SQL.replace("{limit}", String(Math.floor(Number(limit)))),
142+
binds: [],
143+
}
133144
}
134145
if (whType === "bigquery") {
135146
return { sql: BIGQUERY_HISTORY_SQL, binds: [days, limit] }

packages/opencode/src/altimate/native/finops/role-access.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ SELECT
2929
created_on
3030
FROM SNOWFLAKE.ACCOUNT_USAGE.GRANTS_TO_ROLES
3131
WHERE 1=1
32+
{role_filter}
33+
{object_filter}
34+
AND deleted_on IS NULL
35+
ORDER BY granted_on, name
36+
LIMIT ?
3237
`
3338

3439
const SNOWFLAKE_ROLE_HIERARCHY_SQL = `
@@ -52,6 +57,9 @@ SELECT
5257
created_on
5358
FROM SNOWFLAKE.ACCOUNT_USAGE.GRANTS_TO_USERS
5459
WHERE deleted_on IS NULL
60+
{user_filter}
61+
ORDER BY grantee_name, role
62+
LIMIT ?
5563
`
5664

5765
// ---------------------------------------------------------------------------
@@ -69,6 +77,9 @@ SELECT
6977
'' as created_on
7078
FROM \`region-US.INFORMATION_SCHEMA.OBJECT_PRIVILEGES\`
7179
WHERE 1=1
80+
{grantee_filter}
81+
ORDER BY object_type, object_name
82+
LIMIT ?
7283
`
7384

7485
// ---------------------------------------------------------------------------
@@ -86,6 +97,9 @@ SELECT
8697
'' as created_on
8798
FROM system.information_schema.table_privileges
8899
WHERE 1=1
100+
{grantee_filter}
101+
ORDER BY table_name
102+
LIMIT ?
89103
`
90104

91105
// ---------------------------------------------------------------------------
@@ -117,8 +131,9 @@ function buildGrantsSql(
117131
const objF = objectName ? (binds.push(objectName), "AND name = ?") : ""
118132
binds.push(limit)
119133
return {
120-
sql: SNOWFLAKE_GRANTS_ON_SQL +
121-
`${roleF}\n${objF}\nAND deleted_on IS NULL\nORDER BY granted_on, name\nLIMIT ?\n`,
134+
sql: SNOWFLAKE_GRANTS_ON_SQL
135+
.replace("{role_filter}", roleF)
136+
.replace("{object_filter}", objF),
122137
binds,
123138
}
124139
}
@@ -127,8 +142,7 @@ function buildGrantsSql(
127142
const granteeF = role ? (binds.push(role), "AND grantee = ?") : ""
128143
binds.push(limit)
129144
return {
130-
sql: BIGQUERY_GRANTS_SQL +
131-
`${granteeF}\nORDER BY object_type, object_name\nLIMIT ?\n`,
145+
sql: BIGQUERY_GRANTS_SQL.replace("{grantee_filter}", granteeF),
132146
binds,
133147
}
134148
}
@@ -137,8 +151,7 @@ function buildGrantsSql(
137151
const granteeF = role ? (binds.push(role), "AND grantee = ?") : ""
138152
binds.push(limit)
139153
return {
140-
sql: DATABRICKS_GRANTS_SQL +
141-
`${granteeF}\nORDER BY table_name\nLIMIT ?\n`,
154+
sql: DATABRICKS_GRANTS_SQL.replace("{grantee_filter}", granteeF),
142155
binds,
143156
}
144157
}
@@ -250,8 +263,7 @@ export async function queryUserRoles(params: UserRolesParams): Promise<UserRoles
250263
const binds: any[] = []
251264
const userF = params.user ? (binds.push(params.user), "AND grantee_name = ?") : ""
252265
binds.push(limit)
253-
const sql = SNOWFLAKE_USER_ROLES_SQL +
254-
`${userF}\nORDER BY grantee_name, role\nLIMIT ?\n`
266+
const sql = SNOWFLAKE_USER_ROLES_SQL.replace("{user_filter}", userF)
255267

256268
const result = await connector.execute(sql, limit, binds)
257269
const assignments = rowsToRecords(result)

packages/opencode/src/altimate/native/schema/tags.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ SELECT
2626
column_name,
2727
domain as object_type
2828
FROM TABLE(INFORMATION_SCHEMA.TAG_REFERENCES_ALL_COLUMNS(?, 'TABLE'))
29+
{tag_filter}
30+
ORDER BY tag_name, object_name
31+
LIMIT ?
2932
`
3033

3134
const SNOWFLAKE_TAG_LIST_SQL = `
@@ -79,8 +82,7 @@ export async function getTags(params: TagsGetParams): Promise<TagsGetResult> {
7982
? (binds.push(params.tag_name), "WHERE tag_name = ?")
8083
: ""
8184
binds.push(limit)
82-
sql = SNOWFLAKE_TAG_REFERENCES_SQL +
83-
`${tagFilter}\nORDER BY tag_name, object_name\nLIMIT ?\n`
85+
sql = SNOWFLAKE_TAG_REFERENCES_SQL.replace("{tag_filter}", tagFilter)
8486
} else {
8587
// Fall back to listing all tags
8688
binds = [limit]

packages/opencode/test/altimate/schema-finops-dbt.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ describe("FinOps: SQL template generation", () => {
141141
test("builds PostgreSQL history SQL", () => {
142142
const built = HistoryTemplates.buildHistoryQuery("postgres", 7, 50)
143143
expect(built?.sql).toContain("pg_stat_statements")
144-
// Postgres driver does not support binds — LIMIT is rendered inline
144+
// Postgres connector does not yet pass binds — LIMIT rendered inline
145145
expect(built?.sql).toContain("LIMIT 50")
146146
expect(built?.binds).toEqual([])
147147
})

0 commit comments

Comments
 (0)