From 3c579315ff2090fc653353c6e9441d1c752f9e0a Mon Sep 17 00:00:00 2001 From: "chandr-andr (Kiselev Aleksandr)" Date: Thu, 14 Mar 2024 15:16:00 +0100 Subject: [PATCH 1/2] Added new parameter to all execute method. Now it's possible to turn off statement preparation --- python/psqlpy/_internal/__init__.pyi | 28 +++++++ src/driver/connection.rs | 22 +++-- src/driver/connection_pool.rs | 24 ++++-- src/driver/cursor.rs | 118 ++++++++++++++++----------- src/driver/transaction.rs | 108 ++++++++++++++++-------- 5 files changed, 206 insertions(+), 94 deletions(-) diff --git a/python/psqlpy/_internal/__init__.pyi b/python/psqlpy/_internal/__init__.pyi index bdb64188..3583f3b9 100644 --- a/python/psqlpy/_internal/__init__.pyi +++ b/python/psqlpy/_internal/__init__.pyi @@ -321,6 +321,7 @@ class Transaction: self: Self, querystring: str, parameters: list[Any] | None = None, + prepared: bool = True, ) -> QueryResult: """Execute the query. @@ -330,6 +331,8 @@ class Transaction: ### Parameters: - `querystring`: querystring to execute. - `parameters`: list of parameters to pass in the query. + - `prepared`: should the querystring be prepared before the request. + By default any querystring will be prepared. ### Example: ```python @@ -358,6 +361,7 @@ class Transaction: self: Self, querystring: str, parameters: list[list[Any]] | None = None, + prepared: bool = True, ) -> None: ... """Execute query multiple times with different parameters. @@ -367,6 +371,8 @@ class Transaction: ### Parameters: - `querystring`: querystring to execute. - `parameters`: list of list of parameters to pass in the query. + - `prepared`: should the querystring be prepared before the request. + By default any querystring will be prepared. ### Example: ```python @@ -395,6 +401,7 @@ class Transaction: self: Self, querystring: str, parameters: list[Any] | None = None, + prepared: bool = True, ) -> SingleQueryResult: """Fetch exaclty single row from query. @@ -406,6 +413,8 @@ class Transaction: ### Parameters: - `querystring`: querystring to execute. - `parameters`: list of parameters to pass in the query. + - `prepared`: should the querystring be prepared before the request. + By default any querystring will be prepared. ### Example: ```python @@ -434,6 +443,7 @@ class Transaction: self: Self, querystring: str, parameters: list[Any] | None = None, + prepared: bool = True, ) -> Any | None: """Execute the query and return first value of the first row. @@ -443,6 +453,8 @@ class Transaction: ### Parameters: - `querystring`: querystring to execute. - `parameters`: list of parameters to pass in the query. + - `prepared`: should the querystring be prepared before the request. + By default any querystring will be prepared. ### Example: ```python @@ -467,6 +479,7 @@ class Transaction: async def pipeline( self, queries: list[tuple[str, list[Any] | None]], + prepared: bool = True, ) -> list[QueryResult]: """Execute queries in pipeline. @@ -492,6 +505,12 @@ class Transaction: | receive rows 3 | | ``` Read more: https://docs.rs/tokio-postgres/latest/tokio_postgres/#pipelining + + ### Parameters: + - `queries`: queries with parameters to execute. + - `prepared`: should the querystring/querystrings be prepared before the request. + By default any querystrings will be prepared. + ### Example: ```python import asyncio @@ -640,6 +659,7 @@ class Transaction: parameters: list[Any] | None = None, fetch_number: int | None = None, scroll: bool | None = None, + prepared: bool = True, ) -> Cursor: """Create new cursor object. @@ -650,6 +670,8 @@ class Transaction: - `parameters`: list of parameters to pass in the query. - `fetch_number`: how many rows need to fetch. - `scroll`: SCROLL or NO SCROLL cursor. + - `prepared`: should the querystring be prepared before the request. + By default any querystring will be prepared. ### Returns: new initialized cursor. @@ -693,6 +715,7 @@ class Connection: self: Self, querystring: str, parameters: list[Any] | None = None, + prepared: bool = True, ) -> QueryResult: """Execute the query. @@ -702,6 +725,8 @@ class Connection: ### Parameters: - `querystring`: querystring to execute. - `parameters`: list of parameters to pass in the query. + - `prepared`: should the querystring be prepared before the request. + By default any querystring will be prepared. ### Returns: query result as `QueryResult` @@ -788,6 +813,7 @@ class PSQLPool: self: Self, querystring: str, parameters: list[Any] | None = None, + prepared: bool = True, ) -> QueryResult: """Execute the query. @@ -797,6 +823,8 @@ class PSQLPool: ### Parameters: - `querystring`: querystring to execute. - `parameters`: list of parameters to pass in the query. + - `prepared`: should the querystring be prepared before the request. + By default any querystring will be prepared. ### Example: ```python diff --git a/src/driver/connection.rs b/src/driver/connection.rs index 2e01db46..c7f9b0e0 100644 --- a/src/driver/connection.rs +++ b/src/driver/connection.rs @@ -37,17 +37,26 @@ impl RustConnection { &self, querystring: String, params: Vec, + prepared: bool, ) -> RustPSQLDriverPyResult { let db_client = &self.db_client; let mut vec_parameters: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(params.len()); for param in ¶ms { vec_parameters.push(param); } - let statement: tokio_postgres::Statement = db_client.prepare_cached(&querystring).await?; - let result = db_client - .query(&statement, &vec_parameters.into_boxed_slice()) - .await?; + let result = if prepared { + db_client + .query( + &db_client.prepare_cached(&querystring).await?, + &vec_parameters.into_boxed_slice(), + ) + .await? + } else { + db_client + .query(&querystring, &vec_parameters.into_boxed_slice()) + .await? + }; Ok(PSQLDriverPyQueryResult::new(result)) } @@ -104,6 +113,7 @@ impl Connection { py: Python<'a>, querystring: String, parameters: Option<&'a PyAny>, + prepared: Option, ) -> RustPSQLDriverPyResult<&PyAny> { let connection_arc = self.inner_connection.clone(); @@ -112,7 +122,9 @@ impl Connection { params = convert_parameters(parameters)?; } rustengine_future(py, async move { - connection_arc.inner_execute(querystring, params).await + connection_arc + .inner_execute(querystring, params, prepared.unwrap_or(true)) + .await }) } diff --git a/src/driver/connection_pool.rs b/src/driver/connection_pool.rs index 6d0a66ba..eaaf08ae 100644 --- a/src/driver/connection_pool.rs +++ b/src/driver/connection_pool.rs @@ -88,6 +88,7 @@ impl RustPSQLPool { &self, querystring: String, parameters: Vec, + prepared: bool, ) -> RustPSQLDriverPyResult { let db_pool_manager = self .db_pool @@ -103,12 +104,18 @@ impl RustPSQLPool { vec_parameters.push(param); } - let result = db_pool_manager - .query( - &db_pool_manager.prepare_cached(&querystring).await?, - &vec_parameters.into_boxed_slice(), - ) - .await?; + let result = if prepared { + db_pool_manager + .query( + &db_pool_manager.prepare_cached(&querystring).await?, + &vec_parameters.into_boxed_slice(), + ) + .await? + } else { + db_pool_manager + .query(&querystring, &vec_parameters.into_boxed_slice()) + .await? + }; Ok(PSQLDriverPyQueryResult::new(result)) } @@ -256,6 +263,7 @@ impl PSQLPool { py: Python<'a>, querystring: String, parameters: Option<&'a PyAny>, + prepared: Option, ) -> RustPSQLDriverPyResult<&'a PyAny> { let engine_arc = self.rust_psql_pool.clone(); let mut params: Vec = vec![]; @@ -266,7 +274,9 @@ impl PSQLPool { rustengine_future(py, async move { let engine_guard = engine_arc.read().await; - engine_guard.inner_execute(querystring, params).await + engine_guard + .inner_execute(querystring, params, prepared.unwrap_or(true)) + .await }) } } diff --git a/src/driver/cursor.rs b/src/driver/cursor.rs index 9f184b24..ff6dd2ce 100644 --- a/src/driver/cursor.rs +++ b/src/driver/cursor.rs @@ -22,6 +22,7 @@ pub struct InnerCursor { cursor_name: String, fetch_number: usize, scroll: Option, + prepared: bool, is_started: bool, closed: bool, } @@ -35,6 +36,7 @@ impl InnerCursor { cursor_name: String, scroll: Option, fetch_number: usize, + prepared: bool, ) -> Self { InnerCursor { querystring, @@ -43,6 +45,7 @@ impl InnerCursor { cursor_name, fetch_number, scroll, + prepared, is_started: false, closed: false, } @@ -77,7 +80,7 @@ impl InnerCursor { db_transaction_arc .read() .await - .inner_execute(cursor_init_query, &self.parameters) + .inner_execute(cursor_init_query, &self.parameters, self.prepared) .await?; self.is_started = true; @@ -102,7 +105,7 @@ impl InnerCursor { db_transaction_arc .read() .await - .inner_execute(format!("CLOSE {}", self.cursor_name), vec![]) + .inner_execute(format!("CLOSE {}", self.cursor_name), vec![], false) .await?; self.closed = true; @@ -115,7 +118,11 @@ impl InnerCursor { /// /// # Errors /// May return Err Result if cannot execute query. - pub async fn inner_execute(&self, querystring: String) -> RustPSQLDriverPyResult> { + pub async fn inner_execute( + &self, + querystring: String, + prepared: bool, + ) -> RustPSQLDriverPyResult> { let db_transaction_arc = self.db_transaction.clone(); if !self.is_started { @@ -127,7 +134,7 @@ impl InnerCursor { let result = db_transaction_arc .read() .await - .inner_execute_raw(querystring, vec![]) + .inner_execute_raw(querystring, vec![], prepared) .await?; Ok(result) @@ -219,10 +226,13 @@ impl Cursor { let future = rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH {} FROM {}", - inner_cursor_guard.fetch_number, inner_cursor_guard.cursor_name, - )) + .inner_execute( + format!( + "FETCH {} FROM {}", + inner_cursor_guard.fetch_number, inner_cursor_guard.cursor_name, + ), + false, + ) .await?; if result.is_empty() { @@ -286,10 +296,13 @@ impl Cursor { None => inner_cursor_guard.fetch_number, }; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH {fetch_number} FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!( + "FETCH {fetch_number} FROM {}", + inner_cursor_guard.cursor_name + ), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -307,10 +320,10 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH NEXT FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!("FETCH NEXT FROM {}", inner_cursor_guard.cursor_name), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -328,10 +341,10 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH PRIOR FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!("FETCH PRIOR FROM {}", inner_cursor_guard.cursor_name), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -349,10 +362,10 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH FIRST FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!("FETCH FIRST FROM {}", inner_cursor_guard.cursor_name), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -370,10 +383,10 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH LAST FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!("FETCH LAST FROM {}", inner_cursor_guard.cursor_name), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -395,10 +408,13 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH ABSOLUTE {absolute_number} FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!( + "FETCH ABSOLUTE {absolute_number} FROM {}", + inner_cursor_guard.cursor_name + ), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -420,10 +436,13 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH RELATIVE {relative_number} FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!( + "FETCH RELATIVE {relative_number} FROM {}", + inner_cursor_guard.cursor_name + ), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -441,10 +460,10 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH FORWARD ALL FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!("FETCH FORWARD ALL FROM {}", inner_cursor_guard.cursor_name), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -466,10 +485,13 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH BACKWARD {backward_count} FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!( + "FETCH BACKWARD {backward_count} FROM {}", + inner_cursor_guard.cursor_name + ), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) @@ -487,10 +509,10 @@ impl Cursor { rustengine_future(py, async move { let inner_cursor_guard = inner_cursor_arc.read().await; let result = inner_cursor_guard - .inner_execute(format!( - "FETCH BACKWARD ALL FROM {}", - inner_cursor_guard.cursor_name - )) + .inner_execute( + format!("FETCH BACKWARD ALL FROM {}", inner_cursor_guard.cursor_name), + false, + ) .await?; Ok(PSQLDriverPyQueryResult::new(result)) }) diff --git a/src/driver/transaction.rs b/src/driver/transaction.rs index b2e73a32..40ffcb5f 100644 --- a/src/driver/transaction.rs +++ b/src/driver/transaction.rs @@ -73,6 +73,7 @@ impl RustTransaction { &self, querystring: String, parameters: T, + prepared: bool, ) -> RustPSQLDriverPyResult where T: ValueOrReferenceTo>, @@ -94,12 +95,18 @@ impl RustTransaction { vec_parameters.push(param); } - let statement = self.db_client.prepare_cached(&querystring).await?; - - let result = self - .db_client - .query(&statement, &vec_parameters.into_boxed_slice()) - .await?; + let result = if prepared { + self.db_client + .query( + &self.db_client.prepare_cached(&querystring).await?, + &vec_parameters.into_boxed_slice(), + ) + .await? + } else { + self.db_client + .query(&querystring, &vec_parameters.into_boxed_slice()) + .await? + }; Ok(PSQLDriverPyQueryResult::new(result)) } @@ -123,6 +130,7 @@ impl RustTransaction { &self, querystring: String, parameters: T, + prepared: bool, ) -> RustPSQLDriverPyResult> where T: ValueOrReferenceTo>, @@ -144,12 +152,18 @@ impl RustTransaction { vec_parameters.push(param); } - let statement = self.db_client.prepare_cached(&querystring).await?; - - let result = self - .db_client - .query(&statement, &vec_parameters.into_boxed_slice()) - .await?; + let result = if prepared { + self.db_client + .query( + &self.db_client.prepare_cached(&querystring).await?, + &vec_parameters.into_boxed_slice(), + ) + .await? + } else { + self.db_client + .query(&querystring, &vec_parameters.into_boxed_slice()) + .await? + }; Ok(result) } @@ -171,6 +185,7 @@ impl RustTransaction { &self, querystring: String, parameters: Vec>, + prepared: bool, ) -> RustPSQLDriverPyResult<()> { if !self.is_started { return Err(RustPSQLDriverError::DataBaseTransactionError( @@ -188,16 +203,27 @@ impl RustTransaction { )); } for single_parameters in parameters { - let statement = self.db_client.prepare_cached(&querystring).await?; - self.db_client - .query( - &statement, - &single_parameters - .iter() - .map(|p| p as &(dyn ToSql + Sync)) - .collect::>(), - ) - .await?; + if prepared { + self.db_client + .query( + &self.db_client.prepare_cached(&querystring).await?, + &single_parameters + .iter() + .map(|p| p as &(dyn ToSql + Sync)) + .collect::>(), + ) + .await?; + } else { + self.db_client + .query( + &querystring, + &single_parameters + .iter() + .map(|p| p as &(dyn ToSql + Sync)) + .collect::>(), + ) + .await?; + } } Ok(()) @@ -221,6 +247,7 @@ impl RustTransaction { &self, querystring: String, parameters: Vec, + prepared: bool, ) -> RustPSQLDriverPyResult { if !self.is_started { return Err(RustPSQLDriverError::DataBaseTransactionError( @@ -238,12 +265,18 @@ impl RustTransaction { vec_parameters.push(param); } - let statement = self.db_client.prepare_cached(&querystring).await?; - - let result = self - .db_client - .query_one(&statement, &vec_parameters.into_boxed_slice()) - .await?; + let result = if prepared { + self.db_client + .query_one( + &self.db_client.prepare_cached(&querystring).await?, + &vec_parameters.into_boxed_slice(), + ) + .await? + } else { + self.db_client + .query_one(&querystring, &vec_parameters.into_boxed_slice()) + .await? + }; Ok(PSQLDriverSinglePyQueryResult::new(result)) } @@ -259,10 +292,11 @@ impl RustTransaction { pub async fn inner_pipeline( &self, queries: Vec<(String, Vec)>, + prepared: bool, ) -> RustPSQLDriverPyResult> { let mut futures = vec![]; for (querystring, params) in queries { - let execute_future = self.inner_execute(querystring, params); + let execute_future = self.inner_execute(querystring, params, prepared); futures.push(execute_future); } @@ -617,6 +651,7 @@ impl Transaction { py: Python<'a>, querystring: String, parameters: Option<&'a PyAny>, + prepared: Option, ) -> RustPSQLDriverPyResult<&PyAny> { let transaction_arc = self.transaction.clone(); let mut params: Vec = vec![]; @@ -628,7 +663,7 @@ impl Transaction { transaction_arc .read() .await - .inner_execute(querystring, params) + .inner_execute(querystring, params, prepared.unwrap_or(true)) .await }) } @@ -648,6 +683,7 @@ impl Transaction { py: Python<'a>, querystring: String, parameters: Option<&'a PyList>, + prepared: Option, ) -> RustPSQLDriverPyResult<&PyAny> { let transaction_arc = self.transaction.clone(); let mut params: Vec> = vec![]; @@ -661,7 +697,7 @@ impl Transaction { transaction_arc .read() .await - .inner_execute_many(querystring, params) + .inner_execute_many(querystring, params, prepared.unwrap_or(true)) .await }) } @@ -681,6 +717,7 @@ impl Transaction { py: Python<'a>, querystring: String, parameters: Option<&'a PyList>, + prepared: Option, ) -> RustPSQLDriverPyResult<&PyAny> { let transaction_arc = self.transaction.clone(); let mut params: Vec = vec![]; @@ -692,7 +729,7 @@ impl Transaction { transaction_arc .read() .await - .inner_fetch_row(querystring, params) + .inner_fetch_row(querystring, params, prepared.unwrap_or(true)) .await }) } @@ -713,6 +750,7 @@ impl Transaction { py: Python<'a>, querystring: String, parameters: Option<&'a PyList>, + prepared: Option, ) -> RustPSQLDriverPyResult<&PyAny> { let transaction_arc = self.transaction.clone(); let mut params: Vec = vec![]; @@ -724,7 +762,7 @@ impl Transaction { let first_row = transaction_arc .read() .await - .inner_fetch_row(querystring, params) + .inner_fetch_row(querystring, params, prepared.unwrap_or(true)) .await? .get_inner(); Python::with_gil(|py| match first_row.columns().first() { @@ -747,6 +785,7 @@ impl Transaction { &'a self, py: Python<'a>, queries: Option<&'a PyList>, + prepared: Option, ) -> RustPSQLDriverPyResult<&'a PyAny> { let mut processed_queries: Vec<(String, Vec)> = vec![]; if let Some(queries) = queries { @@ -774,7 +813,7 @@ impl Transaction { transaction_arc .read() .await - .inner_pipeline(processed_queries) + .inner_pipeline(processed_queries, prepared.unwrap_or(true)) .await }) } @@ -945,6 +984,7 @@ impl Transaction { format!("cur{}", self.cursor_num), scroll, fetch_number.unwrap_or(10), + true, ))) } } From 64281e981d03e6e89774d2d1b5f93b6169735ba2 Mon Sep 17 00:00:00 2001 From: "chandr-andr (Kiselev Aleksandr)" Date: Thu, 14 Mar 2024 15:19:21 +0100 Subject: [PATCH 2/2] Added new parameter to all execute method. Now it's possible to turn off statement preparation --- src/driver/transaction.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/driver/transaction.rs b/src/driver/transaction.rs index 40ffcb5f..30dbf95c 100644 --- a/src/driver/transaction.rs +++ b/src/driver/transaction.rs @@ -971,6 +971,7 @@ impl Transaction { parameters: Option<&'a PyAny>, fetch_number: Option, scroll: Option, + prepared: Option, ) -> RustPSQLDriverPyResult { let mut params: Vec = vec![]; if let Some(parameters) = parameters { @@ -984,7 +985,7 @@ impl Transaction { format!("cur{}", self.cursor_num), scroll, fetch_number.unwrap_or(10), - true, + prepared.unwrap_or(true), ))) } }