Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support named query parameters #8384

Merged
merged 29 commits into from
Dec 4, 2023
Merged

Support named query parameters #8384

merged 29 commits into from
Dec 4, 2023

Conversation

Asura7969
Copy link
Contributor

@Asura7969 Asura7969 commented Dec 1, 2023

Which issue does this PR close?

Closes #8245.

Rationale for this change

it might be clearer to use named parameters

What changes are included in this PR?

  • change the with_param_values API
  • add ParamValues struct
  • add test case

Are these changes tested?

test_named_query_parameters

Are there any user-facing changes?

Add named query,like:

let results = ctx
        .sql("SELECT c1, c2 FROM test WHERE c1 > $coo AND c1 < $foo")
        .await?
        .with_param_values(vec![
            ("foo", ScalarValue::UInt32(Some(3))),
            ("coo", ScalarValue::UInt32(Some(0))),
        ])?
        .collect()
        .await?;

@github-actions github-actions bot added sql SQL Planner logical-expr Logical plan and expressions core Core DataFusion crate labels Dec 1, 2023

/// The parameter value corresponding to the placeholder
#[derive(Debug, Clone)]
pub enum ParamValues {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is more appropriate to encapsulate it into a struct

match self {
LogicalPlan::Prepare(prepare_lp) => {
// Verify if the number of params matches the number of values
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to ParamValues(verify method)

) -> Result<Expr> {
expr.transform(&|expr| {
match &expr {
Expr::Placeholder(Placeholder { id, data_type }) => {
if id.is_empty() || id == "$0" {
Copy link
Contributor Author

@Asura7969 Asura7969 Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to ParamValues(get_placeholders_with_values method)

@alamb
Copy link
Contributor

alamb commented Dec 1, 2023

Thanks @Asura7969 -- I hope to review this later today or tomorrow

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @Asura7969 -- this looks great 🙏 ❤️ -- it is embarassing that it wasn't immediately clear that this API can already handle named parameters.

I had a few comment suggestions to make it even more obvious, but I also think this PR could be merged as is and those comments done as follow ons.

Thanks again for the contribution

@@ -126,8 +126,24 @@ impl From<Vec<ScalarValue>> for ParamValues {
}
}

impl From<HashMap<String, ScalarValue>> for ParamValues {
fn from(value: HashMap<String, ScalarValue>) -> Self {
impl<K> From<Vec<(K, ScalarValue)>> for ParamValues
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌 very nice

@@ -1215,7 +1215,7 @@ impl DataFrame {
/// .with_param_values(vec![
/// // value at index 0 --> $1
/// ScalarValue::from(2i64)
/// ].into())?
/// ])?
/// .collect()
/// .await?;
/// assert_batches_eq!(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please also add a demonstration of how to use the hashmap version too so that it is easier to discover by a casual user?

Perhaps add this to the example:

    /// // Note you can also provide named parameters
    /// let results = ctx
    ///   .sql("SELECT a FROM example WHERE b = $my_param")
    ///   .await?
    ///    // replace $my_param with value 2
    ///    // Note you can also use a HashMap as well
    ///   .with_param_values(vec![
    ///      "my_param",
    ///      ScalarValue::from(2i64)
    ///    ])?
    ///   .collect()
    ///   .await?;
    /// assert_batches_eq!(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your comment, I'm done

datafusion/expr/src/logical_plan/plan.rs Show resolved Hide resolved
@alamb
Copy link
Contributor

alamb commented Dec 4, 2023

Thanks @Asura7969 !

@alamb alamb merged commit 37bbd66 into apache:main Dec 4, 2023
22 checks passed
Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again @Asura7969 -- I also proposed a small follow on PR #8418 to add an example to LogicalPlan::with_parameters as well

@Asura7969 Asura7969 deleted the query_params branch December 5, 2023 01:03
appletreeisyellow pushed a commit to appletreeisyellow/datafusion that referenced this pull request Dec 15, 2023
* Minor: Improve the document format of JoinHashMap

* support named query parameters

* cargo fmt

* add `ParamValues` conversion

* improve doc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Core DataFusion crate logical-expr Logical plan and expressions sql SQL Planner
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support named query parameters
2 participants