-
-
Notifications
You must be signed in to change notification settings - Fork 55
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 non prepared statements #25
Conversation
# :nodoc: | ||
def self.fetch_bool(params : HTTP::Params, name, default : Bool) | ||
if value = params[name]? | ||
value.underscore == "true" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Underscore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops. changed to downcase and also I validate the value now.
* rename QueryMethods#prepare to QueryMethods#build * rename Connection#build_statement to Connection#build_prepared_statement * add Connection#build_unprepared_statement * add Connection #prepared and #unprepared dsl methods
* use ?prepared_statements=true|false on connection string (default: true) * make inmutable state in database * make mutable state in connection * change Connection#build to use the current prepared_statements flag to build prepared or unprepared statements.
unprepared statements are executed in any free connection of the pool at the moment of executing them
13e7b78
to
da2831c
Compare
|
||
# builds a statement over a real connection | ||
private def build_statement | ||
@db.pool.checkout.unprepared.build(@query) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather call build_unprepared_statement
directly here, to avoid creating the extra intermediate struct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since it is a struct I would bet llvm will inline that. We could even add the @[AlwaysInline] maybe. I prefer use public api if possible. build_(un)prepared_statements are to be defined by drivers but I wouldn't suggest to use them as public api: they are too verbose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point on the inlining!
LGTM. We seriously need to discuss documentation, though :-P |
Out of curiosity, whats the use case for this? The problem with an uprepared statement is that people start using them, aka PHP in the 90s and early 2000s and start generating SQL injection hell. Is there a solid reason to support using them, or is there something I'm missing here? |
@shayneoneill prepared statement consume resources in the database. With long living connections this could be a problem. There is also no profit in using prepared statements if the statements changes often like in dynamic queries. The author of crystal-pg also vouched for using non prepared statements as per his experience in heroku. SQL injection is independent of prepared/unprepared statements. You can always concatenate ugly strings and submitted. The difference is if you want to keep a handle to that statements for later re-execution without the need to build an execution plan again. |
fixes #3
Breaking changes:
Connection#build
is renamed toConnection#build_prepared_statement
.Connection#build_unprepared_statement
is added.Added:
prepared_statements=true|false
(default:true
) to the connection uri. This is forwarded toDatabase
andConnection
as#prepared_statements? : Bool
Database
andConnection
has also#prepared
and#unprepared
methods that returnQueryMethod
instances to query/exec prepared and unprepared statements despite the connection uri.Connection#prepared(sql : String)
andDatabase#prepared(sql: String)
should be used to create prepared statements explicitly that will be executed later. Note: there is a cache by sql statement so same query is not prepared twice on connection. This is not new, but proper interface was pending.A
SessionMethods
module is added to share code betweenDatabase
andConnection
regarding how to build statements of the different kinds. When transactions are implemented this will be helpful also. This module is generic due to implementation details:Database
works withPoolStatement
andConnection
works withStatement
.cc: @spalladino @asterite