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 non prepared statements #25

Merged
merged 8 commits into from
Dec 13, 2016
Merged

Support non prepared statements #25

merged 8 commits into from
Dec 13, 2016

Conversation

bcardiff
Copy link
Member

@bcardiff bcardiff commented Dec 4, 2016

fixes #3

Breaking changes:

  • Connection#build is renamed to Connection#build_prepared_statement.
  • Connection#build_unprepared_statement is added.

Added:

  • add a prepared_statements=true|false (default: true) to the connection uri. This is forwarded to Database and Connection as #prepared_statements? : Bool
  • Database and Connection has also #prepared and #unprepared methods that return QueryMethod instances to query/exec prepared and unprepared statements despite the connection uri.
  • Connection#prepared(sql : String) and Database#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 between Database and Connection 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 with PoolStatement and Connection works with Statement.

cc: @spalladino @asterite

# :nodoc:
def self.fetch_bool(params : HTTP::Params, name, default : Bool)
if value = params[name]?
value.underscore == "true"
Copy link
Contributor

Choose a reason for hiding this comment

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

Underscore?

Copy link
Member Author

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.

Brian J. Cardiff added 8 commits December 7, 2016 01:50
* 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

# builds a statement over a real connection
private def build_statement
@db.pool.checkout.unprepared.build(@query)
Copy link
Contributor

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

Copy link
Member Author

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.

Copy link
Contributor

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!

@spalladino
Copy link
Contributor

LGTM. We seriously need to discuss documentation, though :-P

@bcardiff bcardiff merged commit 825046e into master Dec 13, 2016
@bcardiff bcardiff deleted the feature/unprepared branch November 8, 2017 02:16
@shayneoneill
Copy link

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?

@bcardiff
Copy link
Member Author

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support non prepared statements
3 participants