Skip to content

Commit b37240c

Browse files
committed
Fix parameter type ordering
Until now, the parameter types were obtained by calling `.values()` on the HashSet of parameter types, but this leads to unpredicable ordering, causing queries to fail because their parameters were often transposed. Instead, sort the parameter types by their names. This should always work because in the postgresql case, the keys are '$1', '$2', etc.
1 parent b47de84 commit b37240c

File tree

1 file changed

+20
-11
lines changed

1 file changed

+20
-11
lines changed

datafusion-postgres/src/handlers.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::collections::HashMap;
12
use std::sync::Arc;
23

34
use async_trait::async_trait;
@@ -138,9 +139,9 @@ impl ExtendedQueryHandler for DfSessionService {
138139
.map_err(|e| PgWireError::ApiError(Box::new(e)))?;
139140

140141
let mut param_types = Vec::with_capacity(params.len());
141-
for param_type in params.into_values() {
142+
for param_type in ordered_param_types(&params).iter() {
142143
if let Some(datatype) = param_type {
143-
let pgtype = into_pg_type(&datatype)?;
144+
let pgtype = into_pg_type(datatype)?;
144145
param_types.push(pgtype);
145146
} else {
146147
param_types.push(Type::UNKNOWN);
@@ -177,15 +178,12 @@ impl ExtendedQueryHandler for DfSessionService {
177178
{
178179
let plan = &portal.statement.statement;
179180

180-
let param_values = datatypes::deserialize_parameters(
181-
portal,
182-
&plan
183-
.get_parameter_types()
184-
.map_err(|e| PgWireError::ApiError(Box::new(e)))?
185-
.values()
186-
.map(|v| v.as_ref())
187-
.collect::<Vec<Option<&DataType>>>(),
188-
)?;
181+
let param_types = plan
182+
.get_parameter_types()
183+
.map_err(|e| PgWireError::ApiError(Box::new(e)))?;
184+
185+
let param_values =
186+
datatypes::deserialize_parameters(portal, &ordered_param_types(&param_types))?;
189187

190188
let plan = plan
191189
.clone()
@@ -202,3 +200,14 @@ impl ExtendedQueryHandler for DfSessionService {
202200
Ok(Response::Query(resp))
203201
}
204202
}
203+
204+
fn ordered_param_types<'a>(
205+
types: &'a HashMap<String, Option<DataType>>,
206+
) -> Vec<Option<&'a DataType>> {
207+
// Datafusion stores the parameters as a map. In our case, the keys will be
208+
// `$1`, `$2` etc. The values will be the parameter types.
209+
210+
let mut types = types.iter().collect::<Vec<_>>();
211+
types.sort_by(|a, b| a.0.cmp(&b.0));
212+
types.into_iter().map(|pt| pt.1.as_ref()).collect()
213+
}

0 commit comments

Comments
 (0)