@@ -17,6 +17,7 @@ package queryissue
17
17
18
18
import (
19
19
"slices"
20
+ "strings"
20
21
21
22
mapset "github.com/deckarep/golang-set/v2"
22
23
log "github.com/sirupsen/logrus"
@@ -564,6 +565,75 @@ func (j *JsonPredicateExprDetector) GetIssues() []QueryIssue {
564
565
return issues
565
566
}
566
567
568
+ type NonDecimalIntegerLiteralDetector struct {
569
+ query string
570
+ detected bool
571
+ }
572
+
573
+ func NewNonDecimalIntegerLiteralDetector (query string ) * NonDecimalIntegerLiteralDetector {
574
+ return & NonDecimalIntegerLiteralDetector {
575
+ query : query ,
576
+ }
577
+ }
578
+ func (n * NonDecimalIntegerLiteralDetector ) Detect (msg protoreflect.Message ) error {
579
+ if queryparser .GetMsgFullName (msg ) != queryparser .PG_QUERY_ACONST_NODE {
580
+ return nil
581
+ }
582
+ aConstNode , err := queryparser .ProtoAsAConstNode (msg )
583
+ if err != nil {
584
+ return err
585
+ }
586
+ /*
587
+ Caveats can't report this issue for cases like -
588
+ 1. DML having the constant change to parameters in PGSS - SELECT $1, $2 as binary;
589
+ 2. DDL having the CHECK or DEFAULT -
590
+ - pg_dump will not dump non-decimal literal, it will give out the decimal constant only
591
+ - even if in some user added DDL in schema file during analyze-schema it can't be detected as parse tree doesn't info
592
+ e.g. -
593
+ CREATE TABLE bitwise_example (
594
+ id SERIAL PRIMARY KEY,
595
+ flags INT DEFAULT 0x0F CHECK (flags & 0x01 = 0x01) -- Hexadecimal bitwise check
596
+ );
597
+ parseTree - create_stmt:{relation:{relname:"bitwise_example" inh:true relpersistence:"p" location:15} ...
598
+ table_elts:{column_def:{colname:"flags" type_name:{names:{string:{sval:"pg_catalog"}} names:{string:{sval:"int4"}} typemod:-1
599
+ location:70} is_local:true constraints:{constraint:{contype:CONSTR_DEFAULT raw_expr:{a_const:{ival:{ival:15} location:82}}
600
+ location:74}} constraints:{constraint:{contype:CONSTR_CHECK initially_valid:true raw_expr:{a_expr:{kind:AEXPR_OP name:{string:{sval:"="}}
601
+ lexpr:{a_expr:{kind:AEXPR_OP name:{string:{sval:"&"}} lexpr:{column_ref:{fields:{string:{sval:"flags"}} location:94}} rexpr:{a_const:{ival:{ival:1}
602
+ location:102}} location:100}} rexpr:{a_const:{ival:{ival:1} location:109}} location:107}} ..
603
+
604
+ So mostly be detecting this in PLPGSQL cases
605
+ */
606
+ switch {
607
+ case aConstNode .GetFval () != nil :
608
+ /*
609
+ fval - float val representation in postgres
610
+ ival - integer val
611
+ Fval is only one which stores the non-decimal integers information if used in queries, e.g. SELECT 5678901234, 0o52237223762 as octal;
612
+ select_stmt:{target_list:{res_target:{val:{a_const:{fval:{fval:"5678901234"} location:9}} location:9}}
613
+ target_list:{res_target:{name:"octal" val:{a_const:{fval:{fval:"0o52237223762"} location:21}} location:21}}
614
+
615
+ ival stores the decimal integers if non-decimal is not used in the query, e.g. SELECT 1, 2;
616
+ select_stmt:{target_list:{res_target:{val:{a_const:{ival:{ival:1} location:8}} location:8}}
617
+ target_list:{res_target:{val:{a_const:{ival:{ival:2} location:10}} location:10}}
618
+ */
619
+ fval := aConstNode .GetFval ().Fval
620
+ for _ , literal := range nonDecimalIntegerLiterals {
621
+ if strings .HasPrefix (fval , literal ) {
622
+ n .detected = true
623
+ }
624
+ }
625
+ }
626
+ return nil
627
+ }
628
+
629
+ func (n * NonDecimalIntegerLiteralDetector ) GetIssues () []QueryIssue {
630
+ var issues []QueryIssue
631
+ if n .detected {
632
+ issues = append (issues , NewNonDecimalIntegerLiteralIssue (DML_QUERY_OBJECT_TYPE , "" , n .query ))
633
+ }
634
+ return issues
635
+ }
636
+
567
637
type CommonTableExpressionDetector struct {
568
638
query string
569
639
materializedClauseDetected bool
@@ -580,8 +650,8 @@ func (c *CommonTableExpressionDetector) Detect(msg protoreflect.Message) error {
580
650
return nil
581
651
}
582
652
/*
583
- with_clause:{ctes:{common_table_expr:{ctename:"cte" ctematerialized:CTEMaterializeNever
584
- ctequery:{select_stmt:{target_list:{res_target:{val:{column_ref:{fields:{a_star:{}} location:939}} location:939}} from_clause:{range_var:{relname:"a" inh:true relpersistence:"p" location:946}} limit_option:LIMIT_OPTION_DEFAULT op:SETOP_NONE}} location:906}} location:901} op:SETOP_NONE}} stmt_location:898
653
+ with_clause:{ctes:{common_table_expr:{ctename:"cte" ctematerialized:CTEMaterializeNever
654
+ ctequery:{select_stmt:{target_list:{res_target:{val:{column_ref:{fields:{a_star:{}} location:939}} location:939}} from_clause:{range_var:{relname:"a" inh:true relpersistence:"p" location:946}} limit_option:LIMIT_OPTION_DEFAULT op:SETOP_NONE}} location:906}} location:901} op:SETOP_NONE}} stmt_location:898
585
655
*/
586
656
cteNode , err := queryparser .ProtoAsCTENode (msg )
587
657
if err != nil {
@@ -601,4 +671,3 @@ func (c *CommonTableExpressionDetector) GetIssues() []QueryIssue {
601
671
}
602
672
return issues
603
673
}
604
-
0 commit comments