Skip to content

Commit

Permalink
Added alias handling
Browse files Browse the repository at this point in the history
Introduced outer alias for JoinExpr inorder to bring the source table
and cross join subquery under one alias. This helps tackle the TSQL
unpivot expected vs Postgres alias mismatch while referencing columns in
target list/ other parts of the query.

Task: BABEL-4307
Signed-off-by: “manisha-deshpande” <“[email protected]”>
  • Loading branch information
“manisha-deshpande” committed Jan 14, 2025
1 parent c5c76c0 commit 5891eb6
Show file tree
Hide file tree
Showing 5 changed files with 440 additions and 204 deletions.
43 changes: 19 additions & 24 deletions contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c
Original file line number Diff line number Diff line change
Expand Up @@ -2072,6 +2072,8 @@ tsql_unpivot_debug_transformation(List *components)
//List *unpivot_cols;
char *measure_colname;
char *dim_colname;
char *inner_alias_name;



/* Extract components */
Expand Down Expand Up @@ -2155,7 +2157,8 @@ tsql_unpivot_debug_transformation(List *components)
strcmp(strVal(linitial(prev_unpivot)), "UNPIVOT") == 0)
{
/* Use the alias from previous UNPIVOT */
source_alias = strVal(list_nth(prev_unpivot, 4));
//source_alias = strVal(list_nth(prev_unpivot, 1));
source_alias = strVal(list_nth(prev_unpivot, 1));
/* Use the transformed node as our left arg */
//n->larg = (Node *)list_nth(prev_unpivot, 5);

Expand All @@ -2174,7 +2177,8 @@ tsql_unpivot_debug_transformation(List *components)
errmsg("Invalid source structure for UNPIVOT operation")));
}
n->larg = table_ref;
/* Build VALUES list from source columns */

/* Build VALUES list from source columns */
foreach(lc, source_cols)
{
String *col_name = (String *)lfirst(lc);
Expand Down Expand Up @@ -2203,37 +2207,28 @@ tsql_unpivot_debug_transformation(List *components)
values_subquery->valuesLists = values_list;
rarg->subquery = (Node *)values_subquery;

/* Handle alias for VALUES clause */
/* TODO: can remove check or add error: UNPIVOT table alias cannot be NULL
throw error in parser rule body if alias is NULL */
/* Handle alias for Join-Values (RangeSubSelect) clause */
inner_alias_name = psprintf("%s_1", alias->aliasname);
if (alias != NULL)
{
rarg->alias = alias;
/* Add column names if not specified */
/* TODO: alias->colnames wont exist in the alias object of UNPIVOT stmt so can remove check*/
if (rarg->alias->colnames == NIL)
{
rarg->alias->colnames = list_make2(
makeString(measure_colname),
makeString(dim_colname)
);
}
rarg->alias = makeAlias(inner_alias_name, list_make2(
makeString(measure_colname),
makeString(dim_colname)
)
);
}
else
{
/* Create default alias if none provided */
rarg->alias = makeAlias(
"unpvt",
list_make2(
makeString(measure_colname),
makeString(dim_colname)
)
);
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("Alias for UNPIVOT operation is required.")));
}

n->rarg = (Node *)rarg;
n->usingClause = NIL;
n->quals = NULL;
/* Rewrite by adding unpivot alias as the complete Join operation alias */
n->alias = alias;

elog(DEBUG1, "Final transformed node: %s", nodeToString((Node *)n));

Expand All @@ -2249,7 +2244,7 @@ tsql_unpivot_debug_transformation(List *components)
/* Create result info list */
result_info = list_make5(
makeString("UNPIVOT"),
makeString(rarg->alias->aliasname), /* unpivot alias and its columns: */
makeString(alias->aliasname), /* unpivot alias and its columns: */
makeString(dim_colname), /* dimension column */
makeString(measure_colname), /* measure column */
makeString(source_alias) /* source table/query alias */
Expand Down
230 changes: 50 additions & 180 deletions contrib/babelfishpg_tsql/src/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ static SortByNulls unique_constraint_nulls_ordering(ConstrType constraint_type,
SortByDir ordering);
static void transform_pivot_clause(ParseState *pstate, SelectStmt *stmt);
static void transform_unpivot_clause(ParseState *pstate, SelectStmt *stmt);
static void transform_unpivot_clause_recursive(Node **node, Node **where_clause);
static void transform_unpivot_clause_recursive(Node **node, Node **where_clause, List **dim_cols, char **outer_alias);
/*****************************************
* Commands Hooks
*****************************************/
Expand Down Expand Up @@ -5325,190 +5325,75 @@ transform_pivot_clause(ParseState *pstate, SelectStmt *stmt)
wrapperSelect_RangeFunction->functions = list_make1(list_make2((Node *) pivot_func, NIL));
}

// static List *
// handle_unpivot_star_expansion(ParseState *pstate, SelectStmt *stmt,
// List *source_cols, char *unpivot_alias,
// char *measure_colname, char *dim_colname,
// char *source_table_alias)
// {
// Query *temp_src_query;
// List *temp_src_targetlist;
// List *new_targetlist = NIL;
// List *used_names = NIL;
// bool has_ambiguous_refs = false;

// /* First analyze the source query to get correct target list */
// temp_src_query = parse_sub_analyze((Node *) stmt->srcSql, pstate, NULL,
// false, false);
// temp_src_targetlist = temp_src_query->targetList;

// /* First pass: check for ambiguous references */
// for (int i = 0; i < temp_src_targetlist->length; i++)
// {
// TargetEntry *tempEntry = list_nth_node(TargetEntry, temp_src_targetlist, i);
// char *colName = tempEntry->resname;
// ListCell *lc;

// foreach(lc, used_names)
// {
// if (strcmp(colName, strVal(lfirst(lc))) == 0)
// {
// has_ambiguous_refs = true;
// break;
// }
// }
// used_names = lappend(used_names, makeString(colName));
// }

// /* Get the targetList of the source table excluding unpivot columns */
// for (int i = 0; i < temp_src_targetlist->length; i++)
// {
// ResTarget *tempResTarget;
// TargetEntry *tempEntry = list_nth_node(TargetEntry, temp_src_targetlist, i);
// char *colName = tempEntry->resname;
// bool skip_column = false;
// ListCell *source_lc;
// List *col_fields = NIL;

// /* Skip if column is in source_cols list */
// foreach(source_lc, source_cols)
// {
// String *source_col = (String *) lfirst(source_lc);
// if (strcmp(colName, strVal(source_col)) == 0)
// {
// skip_column = true;
// break;
// }
// }

// if (!skip_column)
// {
// /* Handle ambiguous references by qualifying with table alias */
// if (has_ambiguous_refs && source_table_alias)
// {
// col_fields = list_make2(
// makeString(source_table_alias),
// makeString(colName)
// );
// }
// else
// {
// col_fields = list_make1(makeString(colName));
// }

// /* prepare target list entry */
// tempResTarget = make_restarget_from_cstr_list(col_fields);

// /* Set explicit column name to avoid ambiguity in output */
// if (has_ambiguous_refs && source_table_alias)
// {
// tempResTarget->name = psprintf("%s_%s",
// source_table_alias,
// colName);
// }

// new_targetlist = lappend(new_targetlist, tempResTarget);
// }
// }

// /* Add measure and dimension columns */
// {
// ResTarget *measure_res = makeNode(ResTarget);
// ResTarget *dim_res = makeNode(ResTarget);
// ColumnRef *measure_cref = makeNode(ColumnRef);
// ColumnRef *dim_cref = makeNode(ColumnRef);

// /* Add measure column with explicit alias */
// measure_cref->fields = list_make2(
// makeString(unpivot_alias),
// makeString(measure_colname));
// measure_cref->location = -1;
// measure_res->name = measure_colname; /* Explicit name */
// measure_res->indirection = NIL;
// measure_res->val = (Node *) measure_cref;
// measure_res->location = -1;

// /* Add dimension column with explicit alias */
// dim_cref->fields = list_make2(
// makeString(unpivot_alias),
// makeString(dim_colname));
// dim_cref->location = -1;
// dim_res->name = dim_colname; /* Explicit name */
// dim_res->indirection = NIL;
// dim_res->val = (Node *) dim_cref;
// dim_res->location = -1;

// new_targetlist = lappend(new_targetlist, measure_res);
// new_targetlist = lappend(new_targetlist, dim_res);
// }

// list_free(used_names);
// return new_targetlist;
// }

static void
transform_unpivot_clause(ParseState *pstate, SelectStmt *stmt)
{
Node *where_clause = stmt->whereClause;
// Node *srcSql = (Node *) copyObject(stmt->srcSql);
ListCell *lc;
// Query *temp_query;
// List *temp_targetlist;
// ListCell *tl;
List *dim_cols = NIL;
char *outer_alias = NULL;

foreach(lc, stmt->fromClause)
{
transform_unpivot_clause_recursive((Node**)&(lc->ptr_value), &where_clause);
transform_unpivot_clause_recursive((Node**)&(lc->ptr_value), &where_clause, &dim_cols, &outer_alias);
}

// temp_query = parse_sub_analyze(srcSql,
// pstate,
// NULL,
// false,
// false
// );

// temp_targetlist = temp_query->targetList;

// /* Print each target entry */
// elog(NOTICE, "Target List Entries:");
// foreach(tl, temp_targetlist)
// {
// TargetEntry *te = (TargetEntry *) lfirst(tl);
// elog(NOTICE, "Column: %s, ResNo: %d",
// te->resname ? te->resname : "unnamed",
// te->resno);

// /* Print more details about the expression */
// if (te->expr)
// {
// elog(NOTICE, "Expression type: %d", nodeTag(te->expr));
// elog(NOTICE, "Expression dump: %s", nodeToString(te->expr));
// }
// }
/* Create IS NOT NULL where conditions for all collected columns */
if (outer_alias != NULL && dim_cols != NIL)
{
foreach(lc, dim_cols)
{
char *measure_col = strVal(lfirst(lc));
ColumnRef *measure_ref;
NullTest *null_test;

/* Create IS NOT NULL condition */
measure_ref = makeNode(ColumnRef);
measure_ref->fields = list_make2(makeString(outer_alias),
makeString(measure_col));
measure_ref->location = -1;

null_test = makeNode(NullTest);
null_test->arg = (Expr *)measure_ref;
null_test->nulltesttype = IS_NOT_NULL;
null_test->argisrow = false;
null_test->location = -1;

/* Add to WHERE clause */
if (where_clause)
{
BoolExpr *bool_expr = makeNode(BoolExpr);
bool_expr->boolop = AND_EXPR;
bool_expr->args = list_make2(where_clause, null_test);
bool_expr->location = -1;
where_clause = (Node *)bool_expr;
}
else
{
where_clause = (Node *)null_test;
}
}
}

stmt->whereClause = where_clause;
}

static void transform_unpivot_clause_recursive(Node **node_ptr, Node **where_clause)
static void transform_unpivot_clause_recursive(Node **node_ptr, Node **where_clause, List **dim_cols, char **outer_alias)
{
JoinExpr *join;
List *unpivot_info;
char *unpivot_alias;
char *measure_col;
Node *transformed_node;
ColumnRef *measure_ref;
NullTest *null_test;
BoolExpr *bool_expr;

if (node_ptr == NULL || *node_ptr == NULL)
return;

if (IsA(*node_ptr, JoinExpr))
{
join = (JoinExpr *)*node_ptr;
transform_unpivot_clause_recursive(&join->larg, where_clause);
transform_unpivot_clause_recursive(&join->rarg, where_clause);
transform_unpivot_clause_recursive(&join->larg, where_clause, dim_cols, outer_alias);
transform_unpivot_clause_recursive(&join->rarg, where_clause, dim_cols, outer_alias);
}
else if (IsA(*node_ptr, List))
{
Expand All @@ -5521,34 +5406,19 @@ static void transform_unpivot_clause_recursive(Node **node_ptr, Node **where_cla
measure_col = strVal(list_nth(unpivot_info,3));
transformed_node = list_nth(unpivot_info, 5);

/* Create IS NOT NULL condition */
measure_ref = makeNode(ColumnRef);
measure_ref->fields = list_make2(makeString(unpivot_alias), makeString(measure_col));
measure_ref->location = -1;
/* Update outer_alias with most recent alias */

null_test = makeNode(NullTest);
null_test->arg = (Expr *)measure_ref;
null_test->nulltesttype = IS_NOT_NULL;
null_test->argisrow = false;
null_test->location = -1;

/* Add to WHERE clause */
if (*where_clause)
if (*outer_alias == NULL)
{
bool_expr = makeNode(BoolExpr);
bool_expr->boolop = AND_EXPR;
bool_expr->args = list_make2(*where_clause, null_test);
bool_expr->location = -1;
*where_clause = (Node *)bool_expr;
}
else
{
*where_clause = (Node *)null_test;
*outer_alias = pstrdup(unpivot_alias); // Allocate memory for the string
}

/* Add this measure column to the list */
*dim_cols = lappend(*dim_cols, makeString(measure_col));

/* Replace UNPIVOT info with transformed node and recurse on it */
*node_ptr = transformed_node;
transform_unpivot_clause_recursive(node_ptr, where_clause);
transform_unpivot_clause_recursive(node_ptr, where_clause, dim_cols, outer_alias);
}
}
}
Expand Down
Empty file.
Loading

0 comments on commit 5891eb6

Please sign in to comment.