Project

General

Profile

Feature #24013 » current_trunk_Firebird_and_RedDatabase_support.patch

Andrey Lobanov (RedSoft), 2017-01-23 14:23

View differences:

app/models/user.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
707 707
  # Returns true if the user is allowed to delete the user's own account
708 708
  def own_account_deletable?
709 709
    Setting.unsubscribe? &&
710
      (!admin? || User.active.where("admin = ? AND id <> ?", true, id).exists?)
710
      (!admin? || User.active.where(:admin => true, :id => id).exists?)
711 711
  end
712 712

  
713 713
  safe_attributes 'firstname',
......
844 844
      where(["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]).
845 845
      update_all(['old_value = ?', substitute.id.to_s])
846 846
    JournalDetail.
847
      where(["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]).
848
      update_all(['value = ?', substitute.id.to_s])
847
      where(:property => 'attr', :prop_key => 'assigned_to_id', :value => id.to_s).
848
      update_all(:value => substitute.id.to_s)
849 849
    Message.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
850 850
    News.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
851 851
    # Remove private queries and keep public ones
app/models/issue.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
1587 1587
      if p.priority_derived?
1588 1588
        # priority = highest priority of open children
1589 1589
        # priority is left unchanged if all children are closed and there's no default priority defined
1590
        if priority_position = p.children.open.joins(:priority).maximum("#{IssuePriority.table_name}.position")
1590
        if priority_position = p.children.open.joins(:priority).maximum("#{IssuePriority.table_name}.#{'position'.quote_column_name}")
1591 1591
          p.priority = IssuePriority.find_by_position(priority_position)
1592 1592
        elsif default_priority = IssuePriority.default
1593 1593
          p.priority = default_priority
app/models/query.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
440 440
    json = {}
441 441
    available_filters.each do |field, filter|
442 442
      options = {:type => filter[:type], :name => filter[:name]}
443
      next if filter.is_a?(Hash)
443 444
      options[:remote] = true if filter.remote
444 445

  
445 446
      if has_filter?(field) || !filter.remote
......
933 934
  end
934 935

  
935 936
  def sql_for_custom_field(field, operator, value, custom_field_id)
936
    db_table = CustomValue.table_name
937
    db_field = 'value'
937
    db_table = CustomValue.table_name.quote_table_name
938
    db_field = 'value'.quote_column_name
938 939
    filter = @available_filters[field]
939 940
    return nil unless filter
940 941
    if filter[:field].format.target_class && filter[:field].format.target_class <= User
......
977 978
    filter = available_filters[field]
978 979
    target_class = filter[:through].format.target_class
979 980

  
981
    value_col = 'value'.quote_column_name
982

  
980 983
    "#{queried_table_name}.id #{not_in} IN (" +
981 984
      "SELECT customized_id FROM #{CustomValue.table_name}" +
982 985
      " WHERE customized_type='#{queried_class}' AND custom_field_id=#{custom_field_id}" +
983
      "  AND CAST(CASE value WHEN '' THEN '0' ELSE value END AS decimal(30,0)) IN (" +
986
      "  AND CAST(CASE #{value_col} WHEN '' THEN '0' ELSE #{value_col} END AS decimal(30,0)) IN (" +
984 987
      "  SELECT customized_id FROM #{CustomValue.table_name}" +
985 988
      "  WHERE customized_type='#{target_class}' AND custom_field_id=#{chained_custom_field_id}" +
986
      "  AND #{sql_for_field(field, operator, value, CustomValue.table_name, 'value')}))"
989
      "  AND #{sql_for_field(field, operator, value, CustomValue.table_name, value_col)}))"
987 990
    
988 991
  end
989 992

  
......
999 1002
    filter = available_filters[field]
1000 1003
    target_table_name = filter[:field].format.target_class.table_name
1001 1004

  
1005
    value_col = 'value'.quote_column_name
1006

  
1002 1007
    "#{queried_table_name}.id #{not_in} IN (" +
1003 1008
      "SELECT customized_id FROM #{CustomValue.table_name}" +
1004 1009
      " WHERE customized_type='#{queried_class}' AND custom_field_id=#{custom_field_id}" +
1005
      "  AND CAST(CASE value WHEN '' THEN '0' ELSE value END AS decimal(30,0)) IN (" +
1010
      "  AND CAST(CASE #{value_col} WHEN '' THEN '0' ELSE #{value_col} END AS decimal(30,0)) IN (" +
1006 1011
      "  SELECT id FROM #{target_table_name} WHERE #{sql_for_field(field, operator, value, filter[:field].format.target_class.table_name, attribute)}))"
1007 1012
  end
1008 1013

  
app/models/member.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
34 34
	# Sort by first role and principal
35 35
  scope :sorted, lambda {
36 36
    includes(:member_roles, :roles, :principal).
37
      reorder("#{Role.table_name}.position").
37
      reorder("#{Role.table_name}.#{'position'.quote_column_name}").
38 38
      order(Principal.fields_for_order_statement)
39 39
  }
40 40
  scope :sorted_by_project, lambda {
app/models/project.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
44 44
  has_many :documents, :dependent => :destroy
45 45
  has_many :news, lambda {includes(:author)}, :dependent => :destroy
46 46
  has_many :issue_categories, lambda {order("#{IssueCategory.table_name}.name")}, :dependent => :delete_all
47
  has_many :boards, lambda {order("position ASC")}, :dependent => :destroy
47
  has_many :boards, lambda {order(:position)}, :dependent => :destroy
48 48
  has_one :repository, lambda {where(["is_default = ?", true])}
49 49
  has_many :repositories, :dependent => :destroy
50 50
  has_many :changesets, :through => :repository
51 51
  has_one :wiki, :dependent => :destroy
52 52
  # Custom field for the project issues
53 53
  has_and_belongs_to_many :issue_custom_fields,
54
                          lambda {order("#{CustomField.table_name}.position")},
54
                          lambda {order("#{CustomField.table_name}.#{'position'.quote_column_name}")},
55 55
                          :class_name => 'IssueCustomField',
56 56
                          :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
57 57
                          :association_foreign_key => 'custom_field_id'
app/helpers/my_helper.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
82 82
      limit(10).
83 83
      includes(:status, :project, :tracker, :priority).
84 84
      references(:status, :project, :tracker, :priority).
85
      order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC")
85
      order("#{IssuePriority.table_name}.#{'position'.quote_column_name} DESC, #{Issue.table_name}.updated_on DESC")
86 86
  end
87 87

  
88 88
  def issuesreportedbyme_items
......
117 117
      joins(:activity, :project).
118 118
      references(:issue => [:tracker, :status]).
119 119
      includes(:issue => [:tracker, :status]).
120
      order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC").
120
      order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.#{'position'.quote_column_name} ASC, #{Issue.table_name}.id ASC").
121 121
      to_a
122 122

  
123 123
    return entries, days
app/models/enumeration.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
150 150
    super
151 151
    if position_changed?
152 152
      self.class.where.not(:parent_id => nil).update_all(
153
        "position = coalesce((
154
          select position
155
          from (select id, position from enumerations) as parent
153
        "#{'position'.quote_column_name} = coalesce((
154
          select #{'position'.quote_column_name}
155
          from (select id, #{'position'.quote_column_name} from enumerations) as parent
156 156
          where parent_id = parent.id), 1)"
157 157
      )
158 158
    end
app/models/issue_query.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
23 23
  self.available_columns = [
24 24
    QueryColumn.new(:id, :sortable => "#{Issue.table_name}.id", :default_order => 'desc', :caption => '#', :frozen => true),
25 25
    QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true),
26
    QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true),
26
    QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.#{'position'.quote_column_name}", :groupable => true),
27 27
    QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue),
28
    QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true),
29
    QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true),
28
    QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.#{'position'.quote_column_name}", :groupable => true),
29
    QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.#{'position'.quote_column_name}", :default_order => 'desc', :groupable => true),
30 30
    QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"),
31 31
    QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true),
32 32
    QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true),
app/models/issue_status.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
92 92
    if is_closed_changed? && is_closed == true
93 93
      # First we update issues that have a journal for when the current status was set,
94 94
      # a subselect is used to update all issues with a single query
95
      subselect = "SELECT MAX(j.created_on) FROM #{Journal.table_name} j" +
96
        " JOIN #{JournalDetail.table_name} d ON d.journal_id = j.id" +
97
        " WHERE j.journalized_type = 'Issue' AND j.journalized_id = #{Issue.table_name}.id" +
98
        " AND d.property = 'attr' AND d.prop_key = 'status_id' AND d.value = :status_id"
95
      subselect = Journal.joins(:details).where(:journalized_type => 'Issue').
96
          where("#{Journal.table_name}.journalized_id = #{Issue.table_name}.id").
97
          where(:journal_details => { property: 'attr', prop_key: 'status_id', value: ':status_id'}).
98
          select("MAX(#{Journal.table_name}.created_on)").to_sql
99

  
99 100
      Issue.where(:status_id => id, :closed_on => nil).
100
        update_all(["closed_on = (#{subselect})", {:status_id => id.to_s}])
101
        update_all(["closed_on = (#{subselect})", {:status_id => id}])
101 102

  
102 103
      # Then we update issues that don't have a journal which means the
103 104
      # current status was set on creation
lib/redmine/field_format.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
294 294
      # Returns nil if the custom field can not be used for sorting.
295 295
      def order_statement(custom_field)
296 296
        # COALESCE is here to make sure that blank and NULL values are sorted equally
297
        "COALESCE(#{join_alias custom_field}.value, '')"
297
        "COALESCE(#{join_alias custom_field}.#{'value'.quote_column_name}, '')"
298 298
      end
299 299

  
300 300
      # Returns a GROUP BY clause that can used to group by custom value
......
312 312
          " AND #{alias_name}.customized_id = #{custom_field.class.customized_class.table_name}.id" +
313 313
          " AND #{alias_name}.custom_field_id = #{custom_field.id}" +
314 314
          " AND (#{custom_field.visibility_by_project_condition})" +
315
          " AND #{alias_name}.value <> ''" +
315
          " AND #{alias_name}.#{'value'.quote_column_name} <> ''" +
316 316
          " AND #{alias_name}.id = (SELECT max(#{alias_name}_2.id) FROM #{CustomValue.table_name} #{alias_name}_2" +
317 317
            " WHERE #{alias_name}_2.customized_type = #{alias_name}.customized_type" +
318 318
            " AND #{alias_name}_2.customized_id = #{alias_name}.customized_id" +
......
431 431
        # Make the database cast values into numeric
432 432
        # Postgresql will raise an error if a value can not be casted!
433 433
        # CustomValue validations should ensure that it doesn't occur
434
        "CAST(CASE #{join_alias custom_field}.value WHEN '' THEN '0' ELSE #{join_alias custom_field}.value END AS decimal(30,3))"
434
        value_col = 'value'.quote_column_name
435
        "CAST(CASE #{join_alias custom_field}.#{value_col} WHEN '' THEN '0' ELSE #{join_alias custom_field}.#{value_col} END AS decimal(30,3))"
435 436
      end
436 437

  
437 438
      # Returns totals for the given scope
......
439 440
        scope.joins(:custom_values).
440 441
          where(:custom_values => {:custom_field_id => custom_field.id}).
441 442
          where.not(:custom_values => {:value => ''}).
442
          sum("CAST(#{CustomValue.table_name}.value AS decimal(30,3))")
443
          sum("CAST(#{CustomValue.table_name}.#{'value'.quote_column_name} AS decimal(30,3))")
443 444
      end
444 445

  
445 446
      def cast_total_value(custom_field, value)
......
719 720
      end
720 721

  
721 722
      def group_statement(custom_field)
722
        "COALESCE(#{join_alias custom_field}.value, '')"
723
        "COALESCE(#{join_alias custom_field}.#{'value'.quote_column_name}, '')"
723 724
      end
724 725

  
725 726
      def join_for_order_statement(custom_field)
......
730 731
          " AND #{alias_name}.customized_id = #{custom_field.class.customized_class.table_name}.id" +
731 732
          " AND #{alias_name}.custom_field_id = #{custom_field.id}" +
732 733
          " AND (#{custom_field.visibility_by_project_condition})" +
733
          " AND #{alias_name}.value <> ''" +
734
          " AND #{alias_name}.#{value_column} <> ''" +
734 735
          " AND #{alias_name}.id = (SELECT max(#{alias_name}_2.id) FROM #{CustomValue.table_name} #{alias_name}_2" +
735 736
            " WHERE #{alias_name}_2.customized_type = #{alias_name}.customized_type" +
736 737
            " AND #{alias_name}_2.customized_id = #{alias_name}.customized_id" +
737 738
            " AND #{alias_name}_2.custom_field_id = #{alias_name}.custom_field_id)" +
738 739
          " LEFT OUTER JOIN #{target_class.table_name} #{value_join_alias custom_field}" +
739
          " ON CAST(CASE #{alias_name}.value WHEN '' THEN '0' ELSE #{alias_name}.value END AS decimal(30,0)) = #{value_join_alias custom_field}.id"
740
          " ON CAST(CASE #{alias_name}.#{value_column} WHEN '' THEN '0' ELSE #{alias_name}.#{value_column} END AS decimal(30,0)) = #{value_join_alias custom_field}.id"
740 741
      end
741 742

  
742 743
      def value_join_alias(custom_field)
743 744
        join_alias(custom_field) + "_" + custom_field.field_format
744 745
      end
745 746
      protected :value_join_alias
747

  
748
      def value_column
749
        'value'.quote_column_name
750
      end
751
      protected :value_column
746 752
    end
747 753

  
748 754
    class EnumerationFormat < RecordList
app/models/time_entry_query.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
25 25
    QueryColumn.new(:spent_on, :sortable => ["#{TimeEntry.table_name}.spent_on", "#{TimeEntry.table_name}.created_on"], :default_order => 'desc', :groupable => true),
26 26
    QueryColumn.new(:tweek, :sortable => ["#{TimeEntry.table_name}.spent_on", "#{TimeEntry.table_name}.created_on"], :caption => l(:label_week)),
27 27
    QueryColumn.new(:user, :sortable => lambda {User.fields_for_order_statement}, :groupable => true),
28
    QueryColumn.new(:activity, :sortable => "#{TimeEntryActivity.table_name}.position", :groupable => true),
28
    QueryColumn.new(:activity, :sortable => "#{TimeEntryActivity.table_name}.#{'position'.quote_column_name}", :groupable => true),
29 29
    QueryColumn.new(:issue, :sortable => "#{Issue.table_name}.id"),
30
    QueryAssociationColumn.new(:issue, :tracker, :caption => :field_tracker, :sortable => "#{Tracker.table_name}.position"),
31
    QueryAssociationColumn.new(:issue, :status, :caption => :field_status, :sortable => "#{IssueStatus.table_name}.position"),
30
    QueryAssociationColumn.new(:issue, :tracker, :caption => :field_tracker, :sortable => "#{Tracker.table_name}.#{'position'.quote_column_name}"),
31
    QueryAssociationColumn.new(:issue, :status, :caption => :field_status, :sortable => "#{IssueStatus.table_name}.#{'position'.quote_column_name}"),
32 32
    QueryColumn.new(:comments),
33 33
    QueryColumn.new(:hours, :sortable => "#{TimeEntry.table_name}.hours", :totalable => true),
34 34
  ]
lib/redmine/acts/positioned.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
84 84
          end
85 85
        end
86 86

  
87
        def position_column
88
          'position'.quote_column_name
89
        end
90

  
87 91
        def insert_position
88
          position_scope.where("position >= ? AND id <> ?", position, id).update_all("position = position + 1")
92
          position_scope.where("#{position_column} >= ? AND id <> ?", position, id).update_all("#{position_column} = #{position_column} + 1")
89 93
        end
90 94

  
91 95
        def remove_position
92
          position_scope_was.where("position >= ? AND id <> ?", position_was, id).update_all("position = position - 1")
96
          position_scope_was.where("#{position_column} >= ? AND id <> ?", position_was, id).update_all("#{position_column} = #{position_column} - 1")
93 97
        end
94 98

  
95 99
        def position_scope_changed?
......
99 103
        def shift_positions
100 104
          offset = position_was <=> position
101 105
          min, max = [position, position_was].sort
102
          r = position_scope.where("id <> ? AND position BETWEEN ? AND ?", id, min, max).update_all("position = position + #{offset}")
106
          r = position_scope.where("id <> ? AND #{position_column} BETWEEN ? AND ?", id, min, max).update_all("#{position_column} = #{position_column} + #{offset}")
103 107
          if r != max - min
104 108
            reset_positions_in_list
105 109
          end
lib/redmine/core_ext/string.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
8 8
  def is_binary_data?
9 9
    ( self.count( "^ -~", "^\r\n" ).fdiv(self.size) > 0.3 || self.index( "\x00" ) ) unless empty?
10 10
  end
11

  
12
  def quote_column_name
13
    ActiveRecord::Base.connection.quote_column_name(self)
14
  end
15

  
16
  def quote_table_name
17
    ActiveRecord::Base.connection.quote_table_name(self)
18
  end
11 19
end
app/controllers/projects_controller.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
233 233
  def destroy
234 234
    @project_to_destroy = @project
235 235
    if api_request? || params[:confirm]
236
      @project_to_destroy.destroy
236
      @project_to_destroy.delete
237 237
      respond_to do |format|
238 238
        format.html { redirect_to admin_projects_path }
239 239
        format.api  { render_api_ok }
app/controllers/versions_controller.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
50 50
            includes(:project, :tracker).
51 51
            preload(:status, :priority, :fixed_version).
52 52
            where(:tracker_id => @selected_tracker_ids, :project_id => project_ids, :fixed_version_id => @versions.map(&:id)).
53
            order("#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
53
            order("#{Project.table_name}.lft, #{Tracker.table_name}.#{'position'.quote_column_name}, #{Issue.table_name}.id")
54 54
          @issues_by_version = issues.group_by(&:fixed_version)
55 55
        end
56 56
        @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
......
67 67
        @issues = @version.fixed_issues.visible.
68 68
          includes(:status, :tracker, :priority).
69 69
          preload(:project).
70
          reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id").
70
          reorder("#{Tracker.table_name}.#{'position'.quote_column_name}, #{Issue.table_name}.id").
71 71
          to_a
72 72
      }
73 73
      format.api
app/models/custom_field_enumeration.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
77 77

  
78 78
  def self.fields_for_order_statement(table=nil)
79 79
    table ||= table_name
80
    columns = ['position']
80
    columns = ['position'.quote_column_name]
81 81
    columns.uniq.map {|field| "#{table}.#{field}"}
82 82
  end
83 83

  
app/controllers/application_controller.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
169 169
  def logout_user
170 170
    if User.current.logged?
171 171
      cookies.delete(autologin_cookie_name)
172
      Token.where(["user_id = ? AND action = ?", User.current.id, 'autologin']).delete_all
173
      Token.where(["user_id = ? AND action = ? AND value = ?", User.current.id, 'session', session[:tk]]).delete_all
172
      Token.where(:user_id => User.current.id, :action => 'autologin').delete_all
173
      Token.where(:user_id => User.current.id, :action => 'session', :value => session[:tk]).delete_all
174 174
      self.logged_user = nil
175 175
    end
176 176
  end
lib/plugins/acts_as_searchable/lib/acts_as_searchable.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
112 112
                    search_scope(user, projects, options).
113 113
                    joins(:custom_values).
114 114
                    where(visibility).
115
                    where(search_tokens_condition(["#{CustomValue.table_name}.value"], tokens, options[:all_words])),
115
                    where(search_tokens_condition(["#{CustomValue.table_name}.#{'value'.quote_column_name}"], tokens, options[:all_words])),
116 116
                    options[:limit]
117 117
                  )
118 118
                  queries += 1
lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
27 27
          return if self.included_modules.include?(Redmine::Acts::Customizable::InstanceMethods)
28 28
          cattr_accessor :customizable_options
29 29
          self.customizable_options = options
30
          has_many :custom_values, lambda {includes(:custom_field).order("#{CustomField.table_name}.position")},
30
          has_many :custom_values, lambda {joins(:custom_field).merge(CustomField.order(:position))},
31 31
                                   :as => :customized,
32 32
                                   :inverse_of => :customized,
33 33
                                   :dependent => :delete_all,
db/migrate/20130201184705_add_unique_index_on_tokens_value.rb (revision 7efc8b6462a0dd33ff88b788712d76fec02b0a4c)
2 2
  def up
3 3
    say_with_time "Adding unique index on tokens, this may take some time..." do
4 4
      # Just in case
5
      duplicates = Token.connection.select_values("SELECT value FROM #{Token.table_name} GROUP BY value HAVING COUNT(id) > 1")
5
      duplicates = Token.group(:value).having('COUNT(id) > 1').select(:value).to_a
6 6
      Token.where(:value => duplicates).delete_all
7 7
  
8 8
      add_index :tokens, :value, :unique => true, :name => 'tokens_value'
(8-8/11)