aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/arel
Commit message (Collapse)AuthorAgeFilesLines
* Merge pull request #36492 from kamipo/remove_depth_first_visitorRyuta Kamizono2019-07-253-212/+0
|\ | | | | Remove unused `DepthFirst` visitor
| * Remove unused `DepthFirst` visitorRyuta Kamizono2019-06-153-212/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | We only use `ToSQL` visitors in the our codebase, do not use `DepthFirst` and `Dot` visitors. The `DepthFirst` visitor (which was introduced at c86c37e5f) is used to traverse an Arel (partial) ast with depth first. Is there any worth to keep that undocumented feature with much code and test cases. This removes that unused `DepthFirst` code and test cases.
* | Support beginless ranges in hash conditions.Josh Goodall2019-07-171-2/+2
| | | | | | | | | | | | | | | | | | Ruby 2.7 introduces beginless ranges (..value and ...value) and as with endless ranges we can turn these into inequalities, enabling expressions such as Order.where(created_at: ..1.year.ago) User.where(karma: ...0)
* | Share the Arel dispatch cache between connectionsJean Boussier2019-07-101-1/+1
| |
* | Remove unused `Arel::Attributes.for`Ryuta Kamizono2019-06-152-28/+0
|/ | | | `Arel::Attributes.for` is no longer used since https://github.com/rails/arel/pull/196.
* No allocation `Arel::Visitors::ToSql#visit`Ryuta Kamizono2019-06-153-31/+32
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Each `visit o, collector` allocates one extra array due to receiving args by splat array. https://github.com/rails/rails/blob/2c3332cc4c0fa77dbe2e13e8a792f80fbd8f4ad3/activerecord/lib/arel/visitors/visitor.rb#L27-L29 Currently 1,000 times `User.where(id: 1).to_sql` allocates 13,000 arrays in `visitor.accept`. This avoids receiving args by splat array, it makes `visitor.accept` no array allocation. ```ruby ObjectSpace::AllocationTracer.setup(%i{path line type}) pp ObjectSpace::AllocationTracer.trace { 1_000.times { User.where(id: 1).to_sql } }.select { |k, _| k[2] == :T_ARRAY && k[0].end_with?("visitor.rb", "to_sql.rb") } ``` Before (2c3332cc4c0fa77dbe2e13e8a792f80fbd8f4ad3): ``` {["~/rails/activerecord/lib/arel/visitors/to_sql.rb", 18, :T_ARRAY]=>[1000, 0, 0, 0, 0, 0], ["~/rails/activerecord/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb", 11, :T_ARRAY]=>[1000, 0, 0, 0, 0, 0], ["~/rails/activerecord/lib/arel/visitors/visitor.rb", 12, :T_ARRAY]=>[1000, 0, 0, 0, 0, 0], ["~/rails/activerecord/lib/arel/visitors/to_sql.rb", 788, :T_ARRAY]=>[3000, 0, 0, 0, 0, 0], ["~/rails/activerecord/lib/arel/visitors/to_sql.rb", 794, :T_ARRAY]=>[3000, 0, 0, 0, 0, 0], ["~/rails/activerecord/lib/arel/visitors/to_sql.rb", 156, :T_ARRAY]=>[1000, 0, 0, 0, 0, 0], ["~/rails/activerecord/lib/arel/visitors/to_sql.rb", 443, :T_ARRAY]=>[1000, 0, 0, 0, 0, 0], ["~/rails/activerecord/lib/arel/visitors/to_sql.rb", 603, :T_ARRAY]=>[1000, 0, 0, 0, 0, 0], ["~/rails/activerecord/lib/arel/visitors/to_sql.rb", 611, :T_ARRAY]=>[1000, 0, 0, 0, 0, 0]} ``` After (this change): ``` {} ```
* Enable `Layout/EmptyLinesAroundAccessModifier` copRyuta Kamizono2019-06-1311-11/+0
| | | | | | | | | | | We sometimes say "✂️ newline after `private`" in a code review (e.g. https://github.com/rails/rails/pull/18546#discussion_r23188776, https://github.com/rails/rails/pull/34832#discussion_r244847195). Now `Layout/EmptyLinesAroundAccessModifier` cop have new enforced style `EnforcedStyle: only_before` (https://github.com/rubocop-hq/rubocop/pull/7059). That cop and enforced style will reduce the our code review cost.
* Fix sliced IN clauses to be groupedRyuta Kamizono2019-04-243-114/+49
| | | | | | | Follow up of #35838. And also this refactors `in_clause_length` handling is entirely integrated in Arel visitor.
* Address `ORA-01795: maximum number of expressions in a list is 1000`Yasuo Honda2019-04-112-0/+96
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * To address this error, this commit splits expressions by slices of 1000 elements. * "Oracle Database Error Messages 18c" https://docs.oracle.com/en/database/oracle/oracle-database/18/errmg/ ``` ORA-01795: maximum number of expressions in a list is 1000 Cause: Number of expressions in the query exceeded than 1000. Note that unused column/expressions are also counted Maximum number of expressions that are allowed are 1000. ``` * This commit addresses this ORA-01795 error Note: Actually addressing this error raises another "ORA-00913: too many values" Number of values Oracle database allows is 65535 regardless bind values or literal values. ```ruby $ ARCONN=oracle bin/test test/cases/bind_parameter_test.rb -n test_too_many_binds ... snip ... Error: ActiveRecord::BindParameterTest#test_too_many_binds: ActiveRecord::StatementInvalid: OCIError: ORA-01795: maximum number of expressions in a list is 1000 stmt.c:267:in oci8lib_260.so /home/yahonda/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/ruby-oci8-2.2.7/lib/oci8/cursor.rb:131:in `exec' /home/yahonda/git/oracle-enhanced/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb:142:in `exec' /home/yahonda/git/oracle-enhanced/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb:41:in `block in exec_query' /home/yahonda/git/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:676:in `block (2 levels) in log' /home/yahonda/.rbenv/versions/2.6.2/lib/ruby/2.6.0/monitor.rb:230:in `mon_synchronize' /home/yahonda/git/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:675:in `block in log' /home/yahonda/git/rails/activesupport/lib/active_support/notifications/instrumenter.rb:24:in `instrument' /home/yahonda/git/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:666:in `log' /home/yahonda/git/oracle-enhanced/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb:36:in `log' /home/yahonda/git/oracle-enhanced/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb:24:in `exec_query' /home/yahonda/git/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:484:in `select' /home/yahonda/git/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:70:in `select_all' /home/yahonda/git/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:106:in `select_all' /home/yahonda/git/rails/activerecord/lib/active_record/relation/calculations.rb:299:in `block in execute_simple_calculation' /home/yahonda/git/rails/activerecord/lib/active_record/relation.rb:755:in `skip_query_cache_if_necessary' /home/yahonda/git/rails/activerecord/lib/active_record/relation/calculations.rb:299:in `execute_simple_calculation' /home/yahonda/git/rails/activerecord/lib/active_record/relation/calculations.rb:251:in `perform_calculation' /home/yahonda/git/rails/activerecord/lib/active_record/relation/calculations.rb:141:in `calculate' /home/yahonda/git/rails/activerecord/lib/active_record/relation/calculations.rb:49:in `count' /home/yahonda/git/rails/activerecord/test/cases/bind_parameter_test.rb:113:in `test_too_many_binds' bin/test test/cases/bind_parameter_test.rb:109 .............................F ```
* Revert unused code and re-using query annotation for `update_all` and ↵Ryuta Kamizono2019-04-017-32/+11
| | | | | | | | | | | | | | | | `delete_all` This partly reverts #35617. #35617 includes unused code (for `InsertStatement`) and re-using query annotation for `update_all` and `delete_all`, which has not been discussed yet. If a relation has any annotation, I think it is mostly for SELECT query, so re-using annotation by default is not always desired behavior for me. We should discuss about desired behavior before publishing the implementation.
* Add Relation#annotate for SQL commentingMatt Yoho2019-03-2111-15/+86
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch has two main portions: 1. Add SQL comment support to Arel via Arel::Nodes::Comment. 2. Implement a Relation#annotate method on top of that. == Adding SQL comment support Adds a new Arel::Nodes::Comment node that represents an optional SQL comment and teachers the relevant visitors how to handle it. Comment nodes may be added to the basic CRUD statement nodes and set through any of the four (Select|Insert|Update|Delete)Manager objects. For example: manager = Arel::UpdateManager.new manager.table table manager.comment("annotation") manager.to_sql # UPDATE "users" /* annotation */ This new node type will be used by ActiveRecord::Relation to enable query annotation via SQL comments. == Implementing the Relation#annotate method Implements `ActiveRecord::Relation#annotate`, which accepts a comment string that will be appeneded to any queries generated by the relation. Some examples: relation = Post.where(id: 123).annotate("metadata string") relation.first # SELECT "posts".* FROM "posts" WHERE "posts"."id" = 123 # LIMIT 1 /* metadata string */ class Tag < ActiveRecord::Base scope :foo_annotated, -> { annotate("foo") } end Tag.foo_annotated.annotate("bar").first # SELECT "tags".* FROM "tags" LIMIT 1 /* foo */ /* bar */ Also wires up the plumbing so this works with `#update_all` and `#delete_all` as well. This feature is useful for instrumentation and general analysis of queries generated at runtime.
* Address rubocop offencesRyuta Kamizono2019-03-211-8/+8
|
* Merge pull request #35664 from jeremyevans/remove-roflscalingRafael França2019-03-193-85/+26
|\ | | | | Remove roflscaling
| * Remove roflscaling constantsJeremy Evans2019-03-192-15/+0
| |
| * Remove roflscalingJeremy Evans2019-03-183-70/+26
| | | | | | | | | | | | | | | | | | | | | | roflscaling (using frozen string constants instead of literal strings) was added in 2012, before frozen string literals were added in Ruby 2.3. Now that Rails no longer supports Ruby <2.3, and all of these files use frozen string literals, there is no reason to keep the roflscaling. This does not delete or deprecate the related constants. Such a change can be made in a later commit.
* | Extract `sanitize_as_sql_comment` from SQL visitor into connectionRyuta Kamizono2019-03-194-8/+11
|/ | | | Probably that is useful for any other feature as well.
* Merge pull request #35653 from kamipo/remove_arel_nodes_valuesRyuta Kamizono2019-03-187-60/+9
|\ | | | | Get rid of `Arel::Nodes::Values`
| * Get rid of `Arel::Nodes::Values`Ryuta Kamizono2019-03-187-60/+9
| | | | | | | | | | | | That is completely covered by `Arel::Nodes::ValuesList`. Related https://github.com/rails/arel/pull/484.
* | Add test case to prevent possible SQL injectionRyuta Kamizono2019-03-181-1/+3
|/
* Fix warning: instance variable @optimizer_hints not initializedRyuta Kamizono2019-03-171-0/+1
| | | | https://buildkite.com/rails/rails/builds/59622#924dff9d-85c2-4946-b264-a7e6ce01432c/122-130
* Support Optimizer HintsRyuta Kamizono2019-03-169-2/+56
| | | | | | | | | | | | | | | | | | We as Arm Treasure Data are using Optimizer Hints with a monkey patch (https://gist.github.com/kamipo/4c8539f0ce4acf85075cf5a6b0d9712e), especially in order to use `MAX_EXECUTION_TIME` (refer #31129). Example: ```ruby class Job < ApplicationRecord default_scope { optimizer_hints("MAX_EXECUTION_TIME(50000) NO_INDEX_MERGE(jobs)") } end ``` Optimizer Hints is supported not only for MySQL but also for most databases (PostgreSQL on RDS, Oracle, SQL Server, etc), it is really helpful to turn heavy queries for large scale applications.
* Remove unused `Row` class in `SelectManager`Ryuta Kamizono2019-03-131-12/+0
| | | | The `Row` class is no longer used since d956772b3c61d97940ebcccd7c83e2397ca0c36c.
* Make `And` and `Case` into expression nodesKevin Deisz2019-01-242-4/+2
| | | | Allows aliasing, predications, ordering, and various other functions on `And` and `Case` nodes. This brings them in line with other nodes like `Binary` and `Unary`.
* Alias case nodesKevin Deisz2019-01-211-0/+2
| | | | When `Arel` was merged into `ActiveRecord` we lost the ability to alias case nodes. This adds it back.
* All of queries should return correct result even if including large numberRyuta Kamizono2019-01-182-6/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently several queries cannot return correct result due to incorrect `RangeError` handling. First example: ```ruby assert_equal true, Topic.where(id: [1, 9223372036854775808]).exists? assert_equal true, Topic.where.not(id: 9223372036854775808).exists? ``` The first example is obviously to be true, but currently it returns false. Second example: ```ruby assert_equal topics(:first), Topic.where(id: 1..9223372036854775808).find(1) ``` The second example also should return the object, but currently it raises `RecordNotFound`. It can be seen from the examples, the queries including large number assuming empty result is not always correct. Therefore, This change handles `RangeError` to generate executable SQL instead of raising `RangeError` to users to always return correct result. By this change, it is no longer raised `RangeError` to users.
* Use `unboundable?` rather than `boundable?`Ryuta Kamizono2019-01-182-6/+6
| | | | | | | | | | | | | | | | | | The `unboundable?` behaves like the `infinite?`. ```ruby inf = Topic.predicate_builder.build_bind_attribute(:id, Float::INFINITY) inf.infinite? # => 1 oob = Topic.predicate_builder.build_bind_attribute(:id, 9999999999999999999999999999999) oob.unboundable? # => 1 inf = Topic.predicate_builder.build_bind_attribute(:id, -Float::INFINITY) inf.infinite? # => -1 oob = Topic.predicate_builder.build_bind_attribute(:id, -9999999999999999999999999999999) oob.unboundable? # => -1 ```
* Remove unused `Arel::Compatibility::Wheres`Ryuta Kamizono2019-01-151-35/+0
| | | | This class is no longer used since 9cbfc8a370bf6537a02a2f21e7246dc21ba4cf1f.
* More exercise test cases for `not_between`Ryuta Kamizono2019-01-121-2/+2
| | | | | | And support endless ranges for `not_between` like as `between`. Follow up #34906.
* Support endless ranges in whereGreg Navis2019-01-111-2/+2
| | | | | | This commit adds support for endless ranges, e.g. (1..), that were added in Ruby 2.6. They're functionally equivalent to explicitly specifying Float::INFINITY as the end of the range.
* Enable `Lint/UselessAssignment` cop to avoid unused variable warnings (#34904)Ryuta Kamizono2019-01-093-5/+4
| | | | | | | | | | | | | | * Enable `Lint/UselessAssignment` cop to avoid unused variable warnings Since we've addressed the warning "assigned but unused variable" frequently. 370537de05092aeea552146b42042833212a1acc 3040446cece8e7a6d9e29219e636e13f180a1e03 5ed618e192e9788094bd92c51255dda1c4fd0eae 76ebafe594fc23abc3764acc7a3758ca473799e5 And also, I've found the unused args in c1b14ad which raises no warnings by the cop, it shows the value of the cop.
* Consolidate the duplicated code that building range predicateRyuta Kamizono2019-01-083-12/+16
| | | | | This slightly change the code in the Arel to allow +/-INFINITY as open ended since the Active Record expects that behavior. See 5ecbeda.
* Arel: Implemented DB-aware NULL-safe comparison (#34451)Dmytro Shteflyuk2018-11-1512-0/+130
| | | | | | | | | * Arel: Implemented DB-aware NULL-safe comparison * Fixed where clause inversion for NULL-safe comparison * Renaming "null_safe_eq" to "is_not_distinct_from", "null_safe_not_eq" to "is_distinct_from" [Dmytro Shteflyuk + Rafael Mendonça França]
* Merge pull request #34437 from kbrock/union_all_parenRafael Mendonça França2018-11-132-32/+19
|\ | | | | | | Fix: Arel now emits a single pair of parens for UNION and UNION ALL
| * Emit single pair of parens for UNION and UNION ALLKeenan Brock2018-11-132-32/+19
|/ | | | | | | | mysql has a great implementation to suppress multiple parens for union sql statements. This moves that functionality to the generic implementation This also introduces that functionality for UNION ALL
* Checking boundable not only `IN` clause but also `NOT IN` clauseRyuta Kamizono2018-11-032-0/+16
|
* Fix odd indentationRyuta Kamizono2018-10-101-10/+10
|
* Refactor Arel visitor to use `collect_nodes_for` as much as possibleRyuta Kamizono2018-10-101-33/+10
|
* Improve DELETE with JOIN handling to avoid subqueries if possibleRyuta Kamizono2018-10-102-9/+8
| | | | | | | | | | | | | | Before: ``` Pet Destroy (0.8ms) DELETE FROM `pets` WHERE `pets`.`pet_id` IN (SELECT `pet_id` FROM (SELECT DISTINCT `pets`.`pet_id` FROM `pets` LEFT OUTER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` WHERE `toys`.`name` = ?) AS __active_record_temp) [["name", "Bone"]] ``` After: ``` Pet Destroy (1.0ms) DELETE `pets` FROM `pets` LEFT OUTER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` WHERE `toys`.`name` = ? [["name", "Bone"]] ```
* Simplify the condition in `prepare_update_statement`Ryuta Kamizono2018-10-051-8/+2
|
* Move UPDATE/DELETE with JOIN handling to the Arel sideRyuta Kamizono2018-10-032-37/+80
|
* Handle UPDATE/DELETE with OFFSET in ArelRyuta Kamizono2018-10-015-17/+31
|
* Handle DELETE with LIMIT in ArelRyuta Kamizono2018-09-307-68/+73
| | | | | | | | | | | | | | | | | | MySQL supports DELETE with LIMIT and ORDER BY. https://dev.mysql.com/doc/refman/8.0/en/delete.html Before: ``` Post Destroy (1.0ms) DELETE FROM `posts` WHERE `posts`.`id` IN (SELECT `id` FROM (SELECT `posts`.`id` FROM `posts` WHERE `posts`.`author_id` = ? ORDER BY `posts`.`id` ASC LIMIT ?) __active_record_temp) [["author_id", 1], ["LIMIT", 1]] ``` After: ``` Post Destroy (0.4ms) DELETE FROM `posts` WHERE `posts`.`author_id` = ? ORDER BY `posts`.`id` ASC LIMIT ? [["author_id", 1], ["LIMIT", 1]] ```
* `SQLString#compile` is no longer used since ↵Ryuta Kamizono2018-09-301-4/+0
| | | | 53521a9e39b9d8af4165d7703c36dc905f1f8f67
* `visitor.accept` doesn't handle `&block`Ryuta Kamizono2018-09-301-2/+2
|
* Use private attr_reader in ArelRyuta Kamizono2018-09-303-6/+3
| | | | | | No longer needed workaround for Ruby 2.2 "private attribute?" warning. Related 6d63b5e49a399fe246afcebad45c3c962de268fa.
* Remove `visit_Fixnum` and `visit_Bignum`Ryuta Kamizono2018-09-302-3/+0
| | | | Follow up ae406cd633dab2cafbc0d1bb5922d1ca40056ea0.
* Revert "record who created the node when $DEBUG is true"Ryuta Kamizono2018-09-281-10/+0
| | | | This reverts commit a1b72178714fbf0033fe076b7e51f57eff152bdd.
* Remove `visit_Fixnum` and `visit_Bignum`Ryuta Kamizono2018-09-281-2/+0
| | | | Since Ruby 2.4 unified Fixnum and Bignum into Integer.
* Make `update_counters` preparableRyuta Kamizono2018-09-282-1/+5
| | | | | | | | | | | | | | | | Before: ``` Topic Update All (0.4ms) UPDATE `topics` SET `topics`.`replies_count` = COALESCE(`topics`.`replies_count`, 0) + 1, `topics`.`updated_at` = '2018-09-27 18:34:05.068774' WHERE `topics`.`id` = ? [["id", 7]] ``` After: ``` Topic Update All (0.4ms) UPDATE `topics` SET `topics`.`replies_count` = COALESCE(`topics`.`replies_count`, 0) + ?, `topics`.`updated_at` = ? WHERE `topics`.`id` = ? [["replies_count", 1], ["updated_at", 2018-09-27 18:55:05 UTC], ["id", 7]] ```
* Make `update_all` preparableRyuta Kamizono2018-09-281-0/+4
| | | | | | | | | | | | | | Before: ``` Pet Update All (0.8ms) UPDATE `pets` LEFT OUTER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` SET `pets`.`name` = 'Bob' WHERE `toys`.`name` = ? [["name", "Bone"]] ``` After: ``` Pet Update All (1.1ms) UPDATE `pets` LEFT OUTER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` SET `pets`.`name` = ? WHERE `toys`.`name` = ? [["name", "Bob"], ["name", "Bone"]] ```