Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upPrepared Statement can't be created. #586
Comments
This comment has been minimized.
|
Try declaring |
This comment has been minimized.
Boscop
commented
Jan 27, 2017
•
|
@durango Thanks!
and in my pg_log:
I'm calling it like this: pub fn search(search_terms: &str) -> Result<Vec<Filter>, error::MyError> {
use diesel::prelude::*;
use models::schema::filters::dsl::*;
use diesel::expression::sql_literal::sql;
let query = sql(&format!("EXECUTE search_filters('{}')", search_terms));
query.get_results::<models::filter::Filter>(&*database::connection().get().unwrap()).map_err(|e| e.into())
}Prepared statements are only stored during a session. But what constitutes a session when I'm using a session pool like this? use std::env;
use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;
use r2d2;
lazy_static! {
static ref CONNECTION: r2d2::Pool<ConnectionManager<PgConnection>> = {
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
let config = r2d2::Config::default();
let manager = ConnectionManager::<PgConnection>::new(database_url);
r2d2::Pool::new(config, manager).expect("Failed to create pool")
};
}
pub fn connection() -> r2d2::Pool<ConnectionManager<PgConnection>> {
CONNECTION.clone()
}In my pg_log I notice A LOT of these lines:
Does that mean that after every statement execution I do, the pool drops the connection, and the session ends? If so, what would you do to ensure that the timezone and the prepared statement are always set before any statements are executed? Or is there a way to abstract from that, and make it appear like one continuous session while my server runs? |
This comment has been minimized.
Boscop
commented
Jan 27, 2017
•
|
I figured some stuff out.. use std::env;
use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;
use r2d2;
lazy_static! {
static ref CONNECTION: r2d2::Pool<ConnectionManager<PgConnection>> = {
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
// let config = r2d2::Config::default();
let config = r2d2::Config::builder().connection_customizer(box MyCustomizeConnection).build();
let manager = ConnectionManager::<PgConnection>::new(database_url);
r2d2::Pool::new(config, manager).expect("Failed to create pool")
};
}
pub fn connection() -> r2d2::Pool<ConnectionManager<PgConnection>> {
CONNECTION.clone()
}
use r2d2::CustomizeConnection;
#[derive(Debug)]
struct MyCustomizeConnection;
impl<E> CustomizeConnection<PgConnection, E> for MyCustomizeConnection {
fn on_acquire(&self, conn: &mut PgConnection) -> Result<(), E> {
use diesel::Connection;
use diesel::expression::sql_literal::sql;
use diesel::LoadDsl;
conn.execute("SET TIME ZONE 'UTC';").unwrap();
conn.execute("
PREPARE search_filters(text) AS
WITH ranking AS (
SELECT *
FROM (
SELECT
ts_rank(
to_tsvector('english', filters.name) ||
to_tsvector('english', filters.description) ||
to_tsvector('english', array_to_string(filters.tags, ' '))
, plainto_tsquery($1), 32) AS score,
id,
user_id,
created_at,
updated_at,
name,
description,
code,
params,
tags
FROM filters
) s
WHERE score > 0
ORDER BY score DESC
)
SELECT
id,
user_id,
created_at,
updated_at,
name,
description,
code,
params,
tags
FROM ranking;
").unwrap();
assert_eq!(Ok(1), sql("SELECT count(*) FROM pg_prepared_statements;").get_result::<i64>(conn));
Ok(())
}
} |
This comment has been minimized.
|
I believe so, is everything all sorted out for you? |
This comment has been minimized.
Boscop
commented
Jan 27, 2017
|
Yes, thanks! CREATE OR REPLACE FUNCTION search_filters(search_terms text)
RETURNS SETOF filters AS
$func$
BEGIN
return query
select * from filters
where
ts_rank(to_tsvector('english', filters.name) ||
to_tsvector('english', filters.description) ||
to_tsvector('english', array_to_string(filters.tags, ' ')),
plainto_tsquery(search_terms), 32)
> 0
order by
ts_rank(to_tsvector('english', filters.name) ||
to_tsvector('english', filters.description) ||
to_tsvector('english', array_to_string(filters.tags, ' ')),
plainto_tsquery(search_terms), 32)
desc;
END;
$func$
LANGUAGE 'plpgsql'; |
Boscop commentedJan 20, 2017
I wanted to create a prepared statement to prevent sql injection. I do this whenever my web server starts:
{ use diesel::Connection; database::connection().get().unwrap().execute("SET TIME ZONE 'UTC';").unwrap(); database::connection().get().unwrap().execute(" PREPARE search_filters(text) AS WITH ranking AS ( SELECT * FROM ( SELECT ts_rank( to_tsvector('english', filters.name) || to_tsvector('english', filters.description) || to_tsvector('english', array_to_string(filters.tags, ' ')) , plainto_tsquery($1), 32) AS score, id, user_id, created_at, updated_at, name, description, code, params, tags FROM filters ) s WHERE score > 0 ORDER BY score DESC ) SELECT id, user_id, created_at, updated_at, name, description, code, params, tags FROM ranking; ").unwrap(); use diesel::expression::sql_literal::sql; use diesel::LoadDsl; assert_eq!(Ok(1), sql("SELECT count(*) FROM pg_prepared_statements;").get_result::<i64>(&*database::connection().get().unwrap())); }But the assertion fails, it returns Ok(0), so the prepared statement wasn't created for some reason!
But when I enter this in the postgres cmd line, it says
PREPAREand afterwards that count is 1 and I can call it likesearch_filters('bar').What am I doing wrong here?
Also, how to check if that prepare query returns
PREPAREor something else?