Skip to content

Commit

Permalink
Rewrite scope_identity on some index lookups (yugabyte#94)
Browse files Browse the repository at this point in the history
Currently, a problem arises when using scope_identity to lookup on
an index of identities. Babelfish implemented identity columns using INT
sequences, but scope_identity returns a numeric type. Numeric has higher
precedence than int, so the index column is implicitly cast to a
numeric. However, this means queries that should use an index lookup
instead use a sequential scan, significantly degrading performance.

With this change, if a call to scope_identity or
babelfish_get_last_identity_numeric (used with @@identity) is found in a
where clause compared to an integer, the function is replaced with
babelfish_get_last_identity, which returns an int so the index is used.

Task: BABEL-3384

Signed-off-by: Walt Boettge <[email protected]>
  • Loading branch information
wboettge authored and abhinab-yb committed Nov 14, 2024
1 parent f76a5d2 commit 21e41fb
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/postgres/src/backend/parser/parse_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,54 @@ exprIsNullConstant(Node *arg)
return false;
}

/*
* Helper function for replacing certain calls to scope_identity with
* babelfish_get_last_identity, only when using TSQL.
*
* Fixes an issue where if scope_identity is compared to an identity index.
* scope_identity returns a numeric type, and needs to be rewritten to the
* underlying function that returns an int type so the index is used.
*/
static void
rewrite_scope_identity_call(ParseState *pstate, Node **lexpr, Node **rexpr)
{
Var *col_expr;
FuncExpr *func_expr;
FuncCall *new_call;
char *func_name;

if (sql_dialect != SQL_DIALECT_TSQL)
return;
if (!(*lexpr) || !(*rexpr))
return;

if ((IsA(*lexpr, Var) && IsA(*rexpr, FuncExpr)))
{
col_expr = (Var*) *lexpr;
func_expr = (FuncExpr*) *rexpr;
}
else if (IsA(*lexpr, FuncExpr) && IsA(*rexpr, Var))
{
col_expr = (Var*) *rexpr;
func_expr = (FuncExpr*) *lexpr;
}
else
return;

func_name = get_func_name(func_expr->funcid);
if (strcmp(func_name, "babelfish_get_last_identity_numeric") != 0 &&
strcmp(func_name, "scope_identity") != 0)
return;
if (col_expr->vartype != INT4OID)
return;

new_call = makeFuncCall(list_make1(makeString("babelfish_get_last_identity")), NULL, COERCE_EXPLICIT_CALL, -1);
if (IsA(*rexpr, FuncExpr))
*rexpr = transformFuncCall(pstate, new_call);
else
*lexpr = transformFuncCall(pstate, new_call);
}

static Node *
transformAExprOp(ParseState *pstate, A_Expr *a)
{
Expand Down Expand Up @@ -988,6 +1036,9 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
lexpr = transformExprRecurse(pstate, lexpr);
rexpr = transformExprRecurse(pstate, rexpr);

/* So that where clauses with scope_identity use an index */
rewrite_scope_identity_call(pstate, &lexpr, &rexpr);

result = (Node *) make_op(pstate,
a->name,
lexpr,
Expand Down

0 comments on commit 21e41fb

Please sign in to comment.