rewriteSelectLimit adds or adjusts the LIMIT clause of a SELECT statement using byte-offset positions from the omni AST to surgically edit the original SQL text.
(sql string, sel *ast.SelectStmt, limitCount int)
| 249 | // rewriteSelectLimit adds or adjusts the LIMIT clause of a SELECT statement |
| 250 | // using byte-offset positions from the omni AST to surgically edit the original SQL text. |
| 251 | func rewriteSelectLimit(sql string, sel *ast.SelectStmt, limitCount int) (string, error) { |
| 252 | if sel.LimitCount != nil { |
| 253 | // Already has LIMIT — replace the value if ours is lower. |
| 254 | existingLimit := extractIntFromNode(sel.LimitCount) |
| 255 | if existingLimit > 0 && existingLimit <= limitCount { |
| 256 | return sql, nil // existing limit is already lower or equal, keep it |
| 257 | } |
| 258 | loc := nodeLocOf(sel.LimitCount) |
| 259 | if loc.Start >= 0 && loc.End > loc.Start && loc.End <= len(sql) { |
| 260 | return sql[:loc.Start] + fmt.Sprintf("%d", limitCount) + sql[loc.End:], nil |
| 261 | } |
| 262 | // LimitCount is a non-constant expression (e.g. LIMIT $1, LIMIT (1+2)). |
| 263 | // Cannot safely rewrite in-place; let the caller fall back to CTE wrapper. |
| 264 | return "", errors.Errorf("cannot rewrite non-constant LIMIT expression") |
| 265 | } |
| 266 | |
| 267 | // No LIMIT clause — find the right insertion point. |
| 268 | // PostgreSQL grammar order: ... ORDER BY ... LIMIT ... FOR UPDATE ... |
| 269 | // LIMIT goes BEFORE FOR UPDATE but AFTER everything else. |
| 270 | insertPos, beforeLocking := findLimitInsertPosition(sel) |
| 271 | if beforeLocking { |
| 272 | // Inserting at the start of FOR UPDATE/SHARE. The original whitespace |
| 273 | // before FOR becomes the separator before LIMIT; we add a trailing |
| 274 | // space to separate the limit value from FOR. |
| 275 | return sql[:insertPos] + fmt.Sprintf("LIMIT %d ", limitCount) + sql[insertPos:], nil |
| 276 | } |
| 277 | return sql[:insertPos] + fmt.Sprintf(" LIMIT %d", limitCount) + sql[insertPos:], nil |
| 278 | } |
| 279 | |
| 280 | // findLimitInsertPosition returns the byte offset where " LIMIT N" should be inserted, |
| 281 | // and whether the insertion is before a locking clause (FOR UPDATE/SHARE). |
no test coverage detected