Skip to content

Commit 4159106

Browse files
committed
test(database) :: test that parameters reach the DB and are cached
Before a bound parameter had to survive a round trip in `tests/transactions` and in `computed_projection_binding_order.sql`, but nothing bound one variable twice in a single statement, and nothing asserted that a parameterized page runs as a prepared statement rather than through `SQLExecDirect`. Now two tests cover both halves of [sqlx-oldapi#57](sqlpage/sqlx-oldapi#57), one of wich covers the `INSERT ... SELECT $x WHERE $x IS NOT NULL` shape from #1474.
1 parent f92e1d7 commit 4159106

5 files changed

Lines changed: 82 additions & 0 deletions

File tree

‎tests/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod exec;
99
mod oidc;
1010
mod requests;
1111
mod server_timing;
12+
mod parameter_binding;
1213
pub mod sql_test_files;
1314
mod transactions;
1415
mod uploads;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
select 'text' as component, max(n) as contents from (select $x as n) as t;

‎tests/parameter_binding/mod.rs‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use actix_web::{http::StatusCode, test};
2+
use sqlx::any::AnyKind;
3+
use sqlx::connection::Connection as _;
4+
5+
use sqlpage::webserver::database::SupportedDatabase;
6+
use sqlpage::webserver::http::main_handler;
7+
8+
use crate::common::{get_request_to_with_data, make_app_data};
9+
10+
async fn rendered_page(
11+
path: &str,
12+
data: actix_web::web::Data<sqlpage::AppState>,
13+
) -> actix_web::Result<String> {
14+
let req = get_request_to_with_data(path, data).await?.to_srv_request();
15+
let resp = main_handler(req).await?;
16+
assert_eq!(resp.status(), StatusCode::OK);
17+
Ok(String::from_utf8(test::read_body(resp).await.to_vec()).unwrap())
18+
}
19+
20+
#[actix_web::test]
21+
async fn test_a_parameter_in_a_projection_reaches_the_database() -> actix_web::Result<()> {
22+
let data = make_app_data().await;
23+
let path = match data.db.info.database_type {
24+
SupportedDatabase::Mssql => "/tests/parameter_binding/parameter_in_projection_mssql.sql",
25+
SupportedDatabase::Oracle => return Ok(()), // no CREATE TEMPORARY TABLE
26+
_ => "/tests/parameter_binding/parameter_in_projection.sql",
27+
};
28+
29+
let page = rendered_page(&format!("{path}?x=1447"), data).await?;
30+
assert!(
31+
page.contains("1447"),
32+
"{page}\nexpected the bound parameter to reach the inserted row"
33+
);
34+
Ok(())
35+
}
36+
37+
#[actix_web::test]
38+
async fn test_parameterized_pages_leave_a_prepared_statement_in_the_cache() -> actix_web::Result<()>
39+
{
40+
let data = make_app_data().await;
41+
if data.db.info.kind == AnyKind::Mssql {
42+
return Ok(()); // the MSSQL backend keeps no statement cache
43+
}
44+
45+
for _ in 0..3 {
46+
let page = rendered_page(
47+
"/tests/parameter_binding/echo_parameter.sql?x=1447",
48+
data.clone(),
49+
)
50+
.await?;
51+
assert!(
52+
page.contains("1447"),
53+
"{page}\nexpected the bound parameter to reach the query"
54+
);
55+
}
56+
57+
let connection = data.db.connection.acquire().await.unwrap();
58+
assert!(
59+
connection.cached_statements_size() > 0,
60+
"{:?} ran a parameterized query three times without caching a prepared statement",
61+
data.db.info.kind
62+
);
63+
Ok(())
64+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
DROP TABLE IF EXISTS sqlpage_param_projection;
2+
CREATE TEMPORARY TABLE sqlpage_param_projection(username VARCHAR(100) NOT NULL);
3+
4+
INSERT INTO sqlpage_param_projection (username)
5+
SELECT $x
6+
WHERE $x IS NOT NULL;
7+
8+
select 'text' as component, max(username) as contents from sqlpage_param_projection;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
DROP TABLE IF EXISTS #sqlpage_param_projection;
2+
CREATE TABLE #sqlpage_param_projection(username VARCHAR(100) NOT NULL);
3+
4+
INSERT INTO #sqlpage_param_projection (username)
5+
SELECT $x
6+
WHERE $x IS NOT NULL;
7+
8+
select 'text' as component, max(username) as contents from #sqlpage_param_projection;

0 commit comments

Comments
 (0)