@@ -37,6 +37,7 @@ use crate::event::commit_schema;
37
37
use crate :: metrics:: QUERY_EXECUTE_TIME ;
38
38
use crate :: option:: { Mode , CONFIG } ;
39
39
use crate :: query:: error:: ExecuteError ;
40
+ use crate :: query:: Query as LogicalQuery ;
40
41
use crate :: query:: { TableScanVisitor , QUERY_SESSION } ;
41
42
use crate :: rbac:: role:: { Action , Permission } ;
42
43
use crate :: rbac:: Users ;
@@ -67,69 +68,37 @@ pub async fn query(req: HttpRequest, query_request: Query) -> Result<impl Respon
67
68
let raw_logical_plan = session_state
68
69
. create_logical_plan ( & query_request. query )
69
70
. await ?;
71
+
70
72
// create a visitor to extract the table name
71
73
let mut visitor = TableScanVisitor :: default ( ) ;
72
74
let _ = raw_logical_plan. visit ( & mut visitor) ;
73
- let table_name = visitor
74
- . into_inner ( )
75
- . pop ( )
76
- . ok_or ( QueryError :: MalformedQuery (
77
- "No table found from sql" . to_string ( ) ,
78
- ) ) ?;
75
+
76
+ let tables = visitor. into_inner ( ) ;
79
77
80
78
if CONFIG . parseable . mode == Mode :: Query {
81
- if let Ok ( new_schema) = fetch_schema ( & table_name) . await {
82
- // commit schema merges the schema internally and updates the schema in storage.
83
- commit_schema_to_storage ( & table_name, new_schema. clone ( ) )
84
- . await
85
- . map_err ( QueryError :: ObjectStorage ) ?;
86
- commit_schema ( & table_name, Arc :: new ( new_schema) ) . map_err ( QueryError :: EventError ) ?;
79
+ for table in tables {
80
+ if let Ok ( new_schema) = fetch_schema ( & table) . await {
81
+ // commit schema merges the schema internally and updates the schema in storage.
82
+ commit_schema_to_storage ( & table, new_schema. clone ( ) )
83
+ . await
84
+ . map_err ( QueryError :: ObjectStorage ) ?;
85
+ commit_schema ( & table, Arc :: new ( new_schema) ) . map_err ( QueryError :: EventError ) ?;
86
+ }
87
87
}
88
88
}
89
-
90
- let mut query = into_query ( & query_request, & session_state) . await ?;
89
+ let mut query: LogicalQuery = into_query ( & query_request, & session_state) . await ?;
91
90
92
91
let creds = extract_session_key_from_req ( & req) . expect ( "expects basic auth" ) ;
93
- let permissions = Users . get_permissions ( & creds) ;
92
+ let permissions: Vec < Permission > = Users . get_permissions ( & creds) ;
94
93
95
- // check authorization of this query if it references physical table;
96
- let table_name = query. table_name ( ) ;
97
- if let Some ( ref table) = table_name {
98
- let mut authorized = false ;
99
- let mut tags = Vec :: new ( ) ;
100
-
101
- // in permission check if user can run query on the stream.
102
- // also while iterating add any filter tags for this stream
103
- for permission in permissions {
104
- match permission {
105
- Permission :: Stream ( Action :: All , _) => {
106
- authorized = true ;
107
- break ;
108
- }
109
- Permission :: StreamWithTag ( Action :: Query , ref stream, tag)
110
- if stream == table || stream == "*" =>
111
- {
112
- authorized = true ;
113
- if let Some ( tag) = tag {
114
- tags. push ( tag)
115
- }
116
- }
117
- _ => ( ) ,
118
- }
119
- }
120
-
121
- if !authorized {
122
- return Err ( QueryError :: Unauthorized ) ;
123
- }
124
-
125
- if !tags. is_empty ( ) {
126
- query. filter_tag = Some ( tags)
127
- }
128
- }
94
+ let table_name = query
95
+ . first_table_name ( )
96
+ . ok_or_else ( || QueryError :: MalformedQuery ( "No table name found in query" . to_string ( ) ) ) ?;
97
+ authorize_and_set_filter_tags ( & mut query, permissions, & table_name) ?;
129
98
130
99
let time = Instant :: now ( ) ;
131
100
132
- let ( records, fields) = query. execute ( table_name. clone ( ) . unwrap ( ) ) . await ?;
101
+ let ( records, fields) = query. execute ( table_name. clone ( ) ) . await ?;
133
102
let response = QueryResponse {
134
103
records,
135
104
fields,
@@ -138,16 +107,55 @@ pub async fn query(req: HttpRequest, query_request: Query) -> Result<impl Respon
138
107
}
139
108
. to_http ( ) ;
140
109
141
- if let Some ( table) = table_name {
142
- let time = time. elapsed ( ) . as_secs_f64 ( ) ;
143
- QUERY_EXECUTE_TIME
144
- . with_label_values ( & [ & table] )
145
- . observe ( time) ;
146
- }
110
+ let time = time. elapsed ( ) . as_secs_f64 ( ) ;
111
+
112
+ QUERY_EXECUTE_TIME
113
+ . with_label_values ( & [ & table_name] )
114
+ . observe ( time) ;
147
115
148
116
Ok ( response)
149
117
}
150
118
119
+ fn authorize_and_set_filter_tags (
120
+ query : & mut LogicalQuery ,
121
+ permissions : Vec < Permission > ,
122
+ table_name : & str ,
123
+ ) -> Result < ( ) , QueryError > {
124
+ // check authorization of this query if it references physical table;
125
+ let mut authorized = false ;
126
+ let mut tags = Vec :: new ( ) ;
127
+
128
+ // in permission check if user can run query on the stream.
129
+ // also while iterating add any filter tags for this stream
130
+ for permission in permissions {
131
+ match permission {
132
+ Permission :: Stream ( Action :: All , _) => {
133
+ authorized = true ;
134
+ break ;
135
+ }
136
+ Permission :: StreamWithTag ( Action :: Query , ref stream, tag)
137
+ if stream == table_name || stream == "*" =>
138
+ {
139
+ authorized = true ;
140
+ if let Some ( tag) = tag {
141
+ tags. push ( tag)
142
+ }
143
+ }
144
+ _ => ( ) ,
145
+ }
146
+ }
147
+
148
+ if !authorized {
149
+ return Err ( QueryError :: Unauthorized ) ;
150
+ }
151
+
152
+ if !tags. is_empty ( ) {
153
+ query. filter_tag = Some ( tags)
154
+ }
155
+
156
+ Ok ( ( ) )
157
+ }
158
+
151
159
impl FromRequest for Query {
152
160
type Error = actix_web:: Error ;
153
161
type Future = Pin < Box < dyn Future < Output = Result < Self , Self :: Error > > > > ;
@@ -178,7 +186,7 @@ impl FromRequest for Query {
178
186
async fn into_query (
179
187
query : & Query ,
180
188
session_state : & SessionState ,
181
- ) -> Result < crate :: query :: Query , QueryError > {
189
+ ) -> Result < LogicalQuery , QueryError > {
182
190
if query. query . is_empty ( ) {
183
191
return Err ( QueryError :: EmptyQuery ) ;
184
192
}
0 commit comments