Skip to content

AI Driven Context Enhancements. Add Variable Names to the Casting Hint. #190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 75 additions & 32 deletions src/assign.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ plpgsql_check_assign_to_target_type(PLpgSQL_checkstate *cstate,
Oid target_typoid,
int32 target_typmod,
Oid value_typoid,
bool isnull)
bool isnull,
int targetdno)
{
/* not used yet */
(void) target_typmod;
Expand All @@ -254,12 +255,12 @@ plpgsql_check_assign_to_target_type(PLpgSQL_checkstate *cstate,

if (type_is_rowtype(value_typoid) && !type_is_rowtype(target_typoid))
{
StringInfoData str;
StringInfoData str;

initStringInfo(&str);
appendStringInfo(&str, "cannot cast composite value of \"%s\" type to a scalar value of \"%s\" type",
format_type_be(value_typoid),
format_type_be(target_typoid));
format_type_be(value_typoid),
format_type_be(target_typoid));

plpgsql_check_put_error(cstate,
ERRCODE_DATATYPE_MISMATCH, 0,
Expand All @@ -271,44 +272,86 @@ plpgsql_check_assign_to_target_type(PLpgSQL_checkstate *cstate,
}
else if (!isnull)
{
StringInfoData str;
StringInfoData str;

initStringInfo(&str);
appendStringInfo(&str, "cast \"%s\" value to \"%s\" type",
format_type_be(value_typoid),
format_type_be(target_typoid));
if (targetdno != -1) // && cstate->estate->err_stmt->cmd_type != PLPGSQL_STMT_RETURN)
{
PLpgSQL_var *var = (PLpgSQL_var *) cstate->estate->datums[targetdno];
appendStringInfo(&str, "cast \"%s\" value to \"%s\" type: variable \"%s\"",
format_type_be(value_typoid),
format_type_be(target_typoid),
var->refname);
}
else
{
appendStringInfo(&str, "cast \"%s\" value to \"%s\" type",
format_type_be(value_typoid),
format_type_be(target_typoid));
}

/* accent warning when cast is without supported explicit casting */
if (!can_coerce_type(1, &value_typoid, &target_typoid, COERCION_EXPLICIT))
plpgsql_check_put_error(cstate,
ERRCODE_DATATYPE_MISMATCH, 0,
"target type is different type than source type",
str.data,
"There are no possible explicit coercion between those types, possibly bug!",
PLPGSQL_CHECK_WARNING_OTHERS,
0, NULL, NULL);
ERRCODE_DATATYPE_MISMATCH, 0,
"target type is different type than source type",
str.data,
"There are no possible explicit coercion between those types, possibly bug!",
PLPGSQL_CHECK_WARNING_OTHERS,
0, NULL, NULL);
else if (!can_coerce_type(1, &value_typoid, &target_typoid, COERCION_ASSIGNMENT))
plpgsql_check_put_error(cstate,
ERRCODE_DATATYPE_MISMATCH, 0,
"target type is different type than source type",
str.data,
"The input expression type does not have an assignment cast to the target type.",
PLPGSQL_CHECK_WARNING_OTHERS,
0, NULL, NULL);
ERRCODE_DATATYPE_MISMATCH, 0,
"target type is different type than source type",
str.data,
"The input expression type does not have an assignment cast to the target type.",
PLPGSQL_CHECK_WARNING_OTHERS,
0, NULL, NULL);
else
{
/* highly probably only performance issue */
StringInfoData stmt_info;
initStringInfo(&stmt_info);

if (cstate->estate->err_stmt)
{
switch (cstate->estate->err_stmt->cmd_type)
{
case PLPGSQL_STMT_ASSIGN:
appendStringInfo(&stmt_info, " in assignment statement");
break;
case PLPGSQL_STMT_FETCH:
appendStringInfo(&stmt_info, " in FETCH INTO statement");
break;
case PLPGSQL_STMT_GETDIAG:
appendStringInfo(&stmt_info, " in SELECT INTO statement");
break;
case PLPGSQL_STMT_EXECSQL:
appendStringInfo(&stmt_info, " in EXECUTE statement");
break;
case PLPGSQL_STMT_DYNEXECUTE:
appendStringInfo(&stmt_info, " in EXECUTE USING statement");
break;
default:
appendStringInfo(&stmt_info, " in %s statement",
plpgsql_check__stmt_typename_p(cstate->estate->err_stmt));
}
}

plpgsql_check_put_error(cstate,
ERRCODE_DATATYPE_MISMATCH, 0,
"target type is different type than source type",
str.data,
"Hidden casting can be a performance issue.",
PLPGSQL_CHECK_WARNING_PERFORMANCE,
0, NULL, NULL);
ERRCODE_DATATYPE_MISMATCH, 0,
"target type is different type than source type",
str.data,
psprintf("Hidden casting can be a performance issue%s.", stmt_info.data),
PLPGSQL_CHECK_WARNING_PERFORMANCE,
0, NULL, NULL);

pfree(stmt_info.data);
}

pfree(str.data);
}

elog(NOTICE, "cmd_type: %d", cstate->estate->err_stmt->cmd_type);
}

/*
Expand All @@ -328,7 +371,7 @@ plpgsql_check_assign_tupdesc_dno(PLpgSQL_checkstate *cstate, int varno, TupleDes
plpgsql_check_assign_to_target_type(cstate,
var->datatype->typoid, var->datatype->atttypmod,
TupleDescAttr(tupdesc, 0)->atttypid,
isnull);
isnull, varno);
}
break;

Expand All @@ -350,7 +393,7 @@ plpgsql_check_assign_tupdesc_dno(PLpgSQL_checkstate *cstate, int varno, TupleDes
plpgsql_check_assign_to_target_type(cstate,
typoid, typmod,
TupleDescAttr(tupdesc, 0)->atttypid,
isnull);
isnull, varno);
}
break;

Expand Down Expand Up @@ -421,7 +464,7 @@ plpgsql_check_assign_tupdesc_row_or_rec(PLpgSQL_checkstate *cstate,
var->datatype->typoid,
var->datatype->atttypmod,
valtype,
isnull);
isnull, row->varnos[fnum]);
}
break;

Expand All @@ -435,7 +478,7 @@ plpgsql_check_assign_tupdesc_row_or_rec(PLpgSQL_checkstate *cstate,
expected_typoid,
expected_typmod,
valtype,
isnull);
isnull, target->dno);
}
break;
default:
Expand Down Expand Up @@ -556,7 +599,7 @@ plpgsql_check_recval_assign_tupdesc(PLpgSQL_checkstate *cstate, PLpgSQL_rec *rec
plpgsql_check_assign_to_target_type(cstate,
tattr->atttypid, tattr->atttypmod,
sattr->atttypid,
false);
false, -1);

/* try to search next tuple of fields */
src_field_is_valid = false;
Expand Down
99 changes: 85 additions & 14 deletions src/check_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -719,14 +719,44 @@ check_fishy_qual(PLpgSQL_checkstate *cstate, CachedPlan *cplan, char *query_str)

if (plpgsql_check_qual_has_fishy_cast(pstmt, plan, &param))
{
StringInfoData stmt_info;
initStringInfo(&stmt_info);

if (cstate->estate->err_stmt)
{
switch (cstate->estate->err_stmt->cmd_type)
{
case PLPGSQL_STMT_ASSIGN:
appendStringInfo(&stmt_info, " in assignment statement");
break;
case PLPGSQL_STMT_FETCH:
appendStringInfo(&stmt_info, " in FETCH INTO statement");
break;
case PLPGSQL_STMT_GETDIAG:
appendStringInfo(&stmt_info, " in SELECT INTO statement");
break;
case PLPGSQL_STMT_EXECSQL:
appendStringInfo(&stmt_info, " in EXECUTE statement");
break;
case PLPGSQL_STMT_DYNEXECUTE:
appendStringInfo(&stmt_info, " in EXECUTE USING statement");
break;
default:
appendStringInfo(&stmt_info, " in %s statement",
plpgsql_check__stmt_typename_p(cstate->estate->err_stmt));
}
}

plpgsql_check_put_error(cstate,
ERRCODE_DATATYPE_MISMATCH, 0,
"implicit cast of attribute caused by different PLpgSQL variable type in WHERE clause",
"An index of some attribute cannot be used, when variable, used in predicate, has not right type like a attribute",
"Check a variable type - int versus numeric",
PLPGSQL_CHECK_WARNING_PERFORMANCE,
param->location,
query_str, NULL);
ERRCODE_DATATYPE_MISMATCH, 0,
"implicit cast of attribute caused by different PLpgSQL variable type in WHERE clause",
"An index of some attribute cannot be used, when variable, used in predicate, has not right type like a attribute",
psprintf("Check a variable type - int versus numeric. Hidden casting can be a performance issue%s.", stmt_info.data),
PLPGSQL_CHECK_WARNING_PERFORMANCE,
param->location,
query_str, NULL);

pfree(stmt_info.data);
}
}
}
Expand Down Expand Up @@ -980,7 +1010,7 @@ plpgsql_check_expr_with_scalar_type(PLpgSQL_checkstate *cstate,
plpgsql_check_assign_to_target_type(cstate,
expected_typoid, -1,
TupleDescAttr(tupdesc, 0)->atttypid,
is_immutable_null);
is_immutable_null, -1);

ReleaseTupleDesc(tupdesc);
}
Expand Down Expand Up @@ -1121,7 +1151,7 @@ plpgsql_check_returned_expr(PLpgSQL_checkstate *cstate, PLpgSQL_expr *expr, bool
plpgsql_check_assign_to_target_type(cstate,
func->fn_rettype, -1,
TupleDescAttr(tupdesc, 0)->atttypid,
is_immutable_null);
is_immutable_null, -1);
}
}

Expand Down Expand Up @@ -1314,9 +1344,20 @@ plpgsql_check_expr_as_rvalue(PLpgSQL_checkstate *cstate, PLpgSQL_expr *expr,
StringInfoData str;

initStringInfo(&str);
appendStringInfo(&str, "cast \"%s\" value to \"%s\" type",
format_type_be(value_typoid),
format_type_be(target_typoid));
if (targetdno != -1)
{
PLpgSQL_var *var = (PLpgSQL_var *) cstate->estate->datums[targetdno];
appendStringInfo(&str, "cast \"%s\" value to \"%s\" type: variable \"%s\"",
format_type_be(value_typoid),
format_type_be(target_typoid),
var->refname);
}
else
{
appendStringInfo(&str, "cast \"%s\" value to \"%s\" type",
format_type_be(value_typoid),
format_type_be(target_typoid));
}

/* accent warning when cast is without supported explicit casting */
if (!can_coerce_type(1, &value_typoid, &target_typoid, COERCION_EXPLICIT))
Expand All @@ -1336,15 +1377,45 @@ plpgsql_check_expr_as_rvalue(PLpgSQL_checkstate *cstate, PLpgSQL_expr *expr,
PLPGSQL_CHECK_WARNING_OTHERS,
0, NULL, NULL);
else
{
StringInfoData stmt_info;
initStringInfo(&stmt_info);

if (cstate->estate->err_stmt)
{
switch (cstate->estate->err_stmt->cmd_type)
{
case PLPGSQL_STMT_ASSIGN:
appendStringInfo(&stmt_info, " in assignment statement");
break;
case PLPGSQL_STMT_FETCH:
appendStringInfo(&stmt_info, " in FETCH INTO statement");
break;
case PLPGSQL_STMT_GETDIAG:
appendStringInfo(&stmt_info, " in SELECT INTO statement");
break;
case PLPGSQL_STMT_EXECSQL:
appendStringInfo(&stmt_info, " in EXECUTE statement");
break;
case PLPGSQL_STMT_DYNEXECUTE:
appendStringInfo(&stmt_info, " in EXECUTE USING statement");
break;
default:
appendStringInfo(&stmt_info, " in %s statement",
plpgsql_check__stmt_typename_p(cstate->estate->err_stmt));
}
}

plpgsql_check_put_error(cstate,
ERRCODE_DATATYPE_MISMATCH, 0,
"target type is different type than source type",
str.data,
"Hidden casting can be a performance issue.",
psprintf("Hidden casting can be a performance issue%s.", stmt_info.data),
PLPGSQL_CHECK_WARNING_PERFORMANCE,
0, NULL, NULL);

pfree(str.data);
pfree(stmt_info.data);
}
}
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/plpgsql_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ extern void plpgsql_check_record_variable_usage(PLpgSQL_checkstate *cstate, int
extern void plpgsql_check_row_or_rec(PLpgSQL_checkstate *cstate, PLpgSQL_row *row, PLpgSQL_rec *rec);
extern void plpgsql_check_target(PLpgSQL_checkstate *cstate, int varno, Oid *expected_typoid, int *expected_typmod);
extern void plpgsql_check_assign_to_target_type(PLpgSQL_checkstate *cstate,
Oid target_typoid, int32 target_typmod, Oid value_typoid, bool isnull);
Oid target_typoid, int32 target_typmod, Oid value_typoid, bool isnull, int targetdno);
extern void plpgsql_check_assign_tupdesc_dno(PLpgSQL_checkstate *cstate, int varno, TupleDesc tupdesc, bool isnull);
extern void plpgsql_check_assign_tupdesc_row_or_rec(PLpgSQL_checkstate *cstate,
PLpgSQL_row *row, PLpgSQL_rec *rec, TupleDesc tupdesc, bool isnull);
Expand Down
Loading