Skip to content

Commit c5c5282

Browse files
hiltontjcannonpalmsappletreeisyellowlilicmgattozzi
authored
chore: sync influxdb_pro and bump version to 3.9.1 (#27345)
* chore(sync): influxdb_pro 2026-04-09 Source: 2e22631c718b5b86b26481e070073336655f5571 Co-authored-by: Cannon Palms <cpalms@influxdata.com> Co-authored-by: Chunchun Ye <14298407+appletreeisyellow@users.noreply.github.com> Co-authored-by: Lili Cosic <cosiclili@gmail.com> Co-authored-by: Michael Gattozzi <mgattozzi@influxdata.com> Co-authored-by: Phil Bracikowski <13472206+philjb@users.noreply.github.com> * chore: bump version to 3.9.1 --------- Co-authored-by: Cannon Palms <cpalms@influxdata.com> Co-authored-by: Chunchun Ye <14298407+appletreeisyellow@users.noreply.github.com> Co-authored-by: Lili Cosic <cosiclili@gmail.com> Co-authored-by: Michael Gattozzi <mgattozzi@influxdata.com> Co-authored-by: Phil Bracikowski <13472206+philjb@users.noreply.github.com>
1 parent 0f1816e commit c5c5282

12 files changed

Lines changed: 530 additions & 563 deletions

File tree

Cargo.lock

Lines changed: 86 additions & 86 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ exclude = [
125125
#
126126
# For porting to the actual OSS repo (influxdb), this would need to change to `-nightly`, i.e., by
127127
# stripping the `-oss`.
128-
version = "3.9.0"
128+
version = "3.9.1"
129129
authors = ["InfluxData OSS Developers"]
130130
edition = "2024"
131131
license = "MIT OR Apache-2.0"

influxdb3/src/lib_tests.rs

Lines changed: 0 additions & 93 deletions
This file was deleted.

influxdb3/tests/cli/log_filter.rs

Lines changed: 0 additions & 39 deletions
This file was deleted.

influxdb3/tests/server/query.rs

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,34 @@ async fn api_v3_query_sql_not_found() {
7373
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
7474
}
7575

76+
#[tokio::test]
77+
async fn api_v3_query_sql_invalid_query_should_return_400_bad_request() {
78+
let server = TestServer::spawn().await;
79+
80+
server
81+
.write_lp_to_db("foo", "cpu,host=a usage=1.0 1", Precision::Second)
82+
.await
83+
.unwrap();
84+
85+
let invalid_queries = vec![
86+
"SHOW MEASUREMENTS",
87+
"SELEC * FROM cpu",
88+
"SELECT * cpu",
89+
"SELECT count( FROM cpu",
90+
];
91+
92+
for query in invalid_queries {
93+
let resp = server
94+
.api_v3_query_sql(&[("db", "foo"), ("format", "pretty"), ("q", query)])
95+
.await;
96+
97+
assert!(
98+
resp.status().is_client_error(),
99+
"query should be rejected with 400: {query}"
100+
);
101+
}
102+
}
103+
76104
#[tokio::test]
77105
async fn api_v3_query_sql_params() {
78106
let server = TestServer::spawn().await;
@@ -181,13 +209,7 @@ async fn api_v3_query_sql_params() {
181209
let status = resp.status();
182210
let body = resp.text().await.unwrap();
183211

184-
// TODO - it would be nice if this was a 4xx error, because this is really
185-
// a user error; however, the underlying error that occurs when Logical
186-
// planning is DatafusionError::Internal, and is not so convenient to deal
187-
// with. This may get addressed in:
188-
//
189-
// https://github.com/apache/arrow-datafusion/issues/9738
190-
assert!(status.is_server_error());
212+
assert!(status.is_client_error());
191213
assert_contains!(body, "No value found for placeholder with name $host");
192214
}
193215
}
@@ -523,13 +545,7 @@ async fn api_v3_query_influxql_params() {
523545
let status = resp.status();
524546
let body = resp.text().await.unwrap();
525547

526-
// TODO - it would be nice if this was a 4xx error, because this is really
527-
// a user error; however, the underlying error that occurs when Logical
528-
// planning is DatafusionError::Internal, and is not so convenient to deal
529-
// with. This may get addressed in:
530-
//
531-
// https://github.com/apache/arrow-datafusion/issues/9738
532-
assert!(status.is_server_error());
548+
assert!(status.is_client_error());
533549
assert_contains!(
534550
body,
535551
"Bind parameter '$host' was referenced in the InfluxQL \
@@ -538,6 +554,34 @@ async fn api_v3_query_influxql_params() {
538554
}
539555
}
540556

557+
#[tokio::test]
558+
async fn api_v3_query_influxql_invalid_query_should_return_client_error() {
559+
let server = TestServer::spawn().await;
560+
561+
let invalid_queries = vec![
562+
"show tags",
563+
"show",
564+
"select from",
565+
"select * from",
566+
"show measurements where",
567+
];
568+
569+
for query in invalid_queries {
570+
let resp = server
571+
.api_v3_query_influxql(&[("db", "_internal"), ("q", query), ("format", "pretty")])
572+
.await;
573+
574+
let status = resp.status();
575+
let body = resp.text().await.unwrap();
576+
577+
assert!(
578+
status.is_client_error(),
579+
"query should be rejected as client error: {query}; status={status}; body={body}"
580+
);
581+
assert_contains!(body, "error in InfluxQL statement: parsing error:");
582+
}
583+
}
584+
541585
#[tokio::test]
542586
async fn api_v3_query_json_format() {
543587
let server = TestServer::spawn().await;

influxdb3_server/src/http.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,44 @@ enum Either<L, R> {
609609
Right(R),
610610
}
611611

612+
/// Classify DataFusion errors into HTTP status codes.
613+
///
614+
/// Keep this as the single mapping point so new DataFusion variants can be
615+
/// added in one place.
616+
fn datafusion_error_status_code(err: &DataFusionError) -> StatusCode {
617+
match err {
618+
DataFusionError::Plan(_)
619+
| DataFusionError::NotImplemented(_)
620+
| DataFusionError::SQL(_, _) => StatusCode::BAD_REQUEST,
621+
DataFusionError::Context(_, source) | DataFusionError::Diagnostic(_, source) => {
622+
datafusion_error_status_code(source.as_ref())
623+
}
624+
DataFusionError::Shared(source) => datafusion_error_status_code(source.as_ref()),
625+
DataFusionError::Collection(errors) => {
626+
if errors
627+
.iter()
628+
.all(|error| datafusion_error_status_code(error) == StatusCode::BAD_REQUEST)
629+
{
630+
StatusCode::BAD_REQUEST
631+
} else {
632+
StatusCode::INTERNAL_SERVER_ERROR
633+
}
634+
}
635+
DataFusionError::ArrowError(_, _)
636+
| DataFusionError::ParquetError(_)
637+
| DataFusionError::ObjectStore(_)
638+
| DataFusionError::IoError(_)
639+
| DataFusionError::Internal(_)
640+
| DataFusionError::Configuration(_)
641+
| DataFusionError::SchemaError(_, _)
642+
| DataFusionError::Execution(_)
643+
| DataFusionError::ExecutionJoin(_)
644+
| DataFusionError::ResourcesExhausted(_)
645+
| DataFusionError::External(_)
646+
| DataFusionError::Substrait(_) => StatusCode::INTERNAL_SERVER_ERROR,
647+
}
648+
}
649+
612650
impl IntoResponse for CatalogError {
613651
fn into_response(self) -> Response {
614652
let resp_or_code: Either<Response, StatusCode> = match self {
@@ -676,6 +714,12 @@ impl IntoResponse for Error {
676714
.body(bytes_to_response_body(err.to_string()))
677715
.unwrap()
678716
}
717+
Self::Query(QueryExecutorError::QueryPlanning(err)) | Self::Datafusion(err) => {
718+
ResponseBuilder::new()
719+
.status(datafusion_error_status_code(&err))
720+
.body(bytes_to_response_body(err.to_string()))
721+
.unwrap()
722+
}
679723
Self::WriteBuffer(err @ WriteBufferError::DatabaseNotFound { db_name: _ }) => {
680724
ResponseBuilder::new()
681725
.status(StatusCode::NOT_FOUND)
@@ -862,6 +906,13 @@ impl IntoResponse for Error {
862906
.status(StatusCode::BAD_REQUEST)
863907
.body(bytes_to_response_body(self.to_string()))
864908
.unwrap(),
909+
Self::InfluxqlRewrite(_)
910+
| Self::InfluxqlSingleStatement
911+
| Self::InfluxqlNoDatabase
912+
| Self::InfluxqlDatabaseMismatch { .. } => ResponseBuilder::new()
913+
.status(StatusCode::BAD_REQUEST)
914+
.body(bytes_to_response_body(self.to_string()))
915+
.unwrap(),
865916
Self::Authentication(_) => ResponseBuilder::new()
866917
.status(StatusCode::UNAUTHORIZED)
867918
.body(bytes_to_response_body("".to_string()))
@@ -882,7 +933,35 @@ impl IntoResponse for Error {
882933
.status(StatusCode::NOT_FOUND)
883934
.body(bytes_to_response_body(self.to_string()))
884935
.unwrap(),
885-
_ => ResponseBuilder::new()
936+
Self::NoHandler
937+
| Self::NonUtf8Body(_)
938+
| Self::NonUtf8ContentEncodingHeader(_)
939+
| Self::NonUtf8ContentTypeHeader(_)
940+
| Self::ClientHangup(_)
941+
| Self::RequestSizeExceeded(_)
942+
| Self::InvalidGzip(_)
943+
| Self::InvalidMimeType(_)
944+
| Self::InvalidNamespaceName(_)
945+
| Self::ParseLineProtocol(_)
946+
| Self::RequestLimit
947+
| Self::Unauthenticated
948+
| Self::Forbidden
949+
| Self::ServingHttp(_)
950+
| Self::NonUtf8MimeType(_)
951+
| Self::Arrow(_)
952+
| Self::Hyper(_)
953+
| Self::WriteBuffer(_)
954+
| Self::Persister(_)
955+
| Self::ToStr(_)
956+
| Self::Influxdb3Write(_)
957+
| Self::Io(_)
958+
| Self::Query(_)
959+
| Self::ObjectStore(_)
960+
| Self::PythonPluginsNotEnabled
961+
| Self::Plugin(_)
962+
| Self::ProcessingEngine(_)
963+
| Self::Influxdb3TypesHttp(_)
964+
| Self::LegacyWriteParse(_) => ResponseBuilder::new()
886965
.status(StatusCode::INTERNAL_SERVER_ERROR)
887966
.body(bytes_to_response_body(self.to_string()))
888967
.unwrap(),

0 commit comments

Comments
 (0)