1
1
use graph:: prelude:: BlockNumber ;
2
2
use sqlparser:: ast:: {
3
- Expr , Ident , ObjectName , Query , SetExpr , Statement , TableAlias , TableFactor , VisitMut ,
4
- VisitorMut ,
3
+ Expr , Ident , ObjectName , Offset , Query , SetExpr , Statement , TableAlias , TableFactor , Value ,
4
+ VisitMut , VisitorMut ,
5
5
} ;
6
6
use sqlparser:: parser:: Parser ;
7
7
use std:: result:: Result ;
@@ -22,20 +22,30 @@ pub enum Error {
22
22
NotSelectQuery ,
23
23
#[ error( "Unknown table {0}" ) ]
24
24
UnknownTable ( String ) ,
25
+ #[ error( "Only constant numbers are supported for LIMIT and OFFSET." ) ]
26
+ UnsupportedLimitOffset ,
27
+ #[ error( "The limit of {0} is greater than the maximum allowed limit of {1}." ) ]
28
+ UnsupportedLimit ( u32 , u32 ) ,
29
+ #[ error( "The offset of {0} is greater than the maximum allowed offset of {1}." ) ]
30
+ UnsupportedOffset ( u32 , u32 ) ,
25
31
}
26
32
27
33
pub struct Validator < ' a > {
28
34
layout : & ' a Layout ,
29
35
ctes : HashSet < String > ,
30
36
block : BlockNumber ,
37
+ max_limit : u32 ,
38
+ max_offset : u32 ,
31
39
}
32
40
33
41
impl < ' a > Validator < ' a > {
34
- pub fn new ( layout : & ' a Layout , block : BlockNumber ) -> Self {
42
+ pub fn new ( layout : & ' a Layout , block : BlockNumber , max_limit : u32 , max_offset : u32 ) -> Self {
35
43
Self {
36
44
layout,
37
45
ctes : Default :: default ( ) ,
38
46
block,
47
+ max_limit,
48
+ max_offset,
39
49
}
40
50
}
41
51
@@ -61,6 +71,45 @@ impl<'a> Validator<'a> {
61
71
62
72
Ok ( ( ) )
63
73
}
74
+
75
+ pub fn validate_limit_offset ( & mut self , query : & mut Query ) -> ControlFlow < Error > {
76
+ let Query { limit, offset, .. } = query;
77
+
78
+ if let Some ( limit) = limit {
79
+ match limit {
80
+ Expr :: Value ( Value :: Number ( s, _) ) => match s. parse :: < u32 > ( ) {
81
+ Err ( _) => return ControlFlow :: Break ( Error :: UnsupportedLimitOffset ) ,
82
+ Ok ( limit) => {
83
+ if limit > self . max_limit {
84
+ return ControlFlow :: Break ( Error :: UnsupportedLimit (
85
+ limit,
86
+ self . max_limit ,
87
+ ) ) ;
88
+ }
89
+ }
90
+ } ,
91
+ _ => return ControlFlow :: Break ( Error :: UnsupportedLimitOffset ) ,
92
+ }
93
+ }
94
+
95
+ if let Some ( Offset { value, .. } ) = offset {
96
+ match value {
97
+ Expr :: Value ( Value :: Number ( s, _) ) => match s. parse :: < u32 > ( ) {
98
+ Err ( _) => return ControlFlow :: Break ( Error :: UnsupportedLimitOffset ) ,
99
+ Ok ( offset) => {
100
+ if offset > self . max_offset {
101
+ return ControlFlow :: Break ( Error :: UnsupportedOffset (
102
+ offset,
103
+ self . max_offset ,
104
+ ) ) ;
105
+ }
106
+ }
107
+ } ,
108
+ _ => return ControlFlow :: Break ( Error :: UnsupportedLimitOffset ) ,
109
+ }
110
+ }
111
+ ControlFlow :: Continue ( ( ) )
112
+ }
64
113
}
65
114
66
115
impl VisitorMut for Validator < ' _ > {
@@ -73,20 +122,27 @@ impl VisitorMut for Validator<'_> {
73
122
}
74
123
}
75
124
76
- fn pre_visit_query ( & mut self , _query : & mut Query ) -> ControlFlow < Self :: Break > {
125
+ fn pre_visit_query ( & mut self , query : & mut Query ) -> ControlFlow < Self :: Break > {
77
126
// Add common table expressions to the set of known tables
78
- if let Some ( ref with) = _query . with {
127
+ if let Some ( ref with) = query . with {
79
128
self . ctes . extend (
80
129
with. cte_tables
81
130
. iter ( )
82
131
. map ( |cte| cte. alias . name . value . to_lowercase ( ) ) ,
83
132
) ;
84
133
}
85
134
86
- match * _query. body {
87
- SetExpr :: Update ( _) | SetExpr :: Insert ( _) => ControlFlow :: Break ( Error :: NotSelectQuery ) ,
88
- _ => ControlFlow :: Continue ( ( ) ) ,
135
+ match * query. body {
136
+ SetExpr :: Select ( _) | SetExpr :: Query ( _) => { /* permitted */ }
137
+ SetExpr :: SetOperation { .. } => { /* permitted */ }
138
+ SetExpr :: Table ( _) => { /* permitted */ }
139
+ SetExpr :: Values ( _) => { /* permitted */ }
140
+ SetExpr :: Insert ( _) | SetExpr :: Update ( _) => {
141
+ return ControlFlow :: Break ( Error :: NotSelectQuery )
142
+ }
89
143
}
144
+
145
+ self . validate_limit_offset ( query)
90
146
}
91
147
92
148
/// Invoked for any table function in the AST.
0 commit comments