- # Match any object (evidently a group or user) whose UUID is
- # listed explicitly in user_uuids.
- sql_conds += ["#{sql_table}.uuid in (:user_uuids)"]
-
- # Match any object whose owner is listed explicitly in
- # user_uuids.
- sql_conds += ["#{sql_table}.owner_uuid IN (:user_uuids)"]
-
- # At least read permission from user_uuid to target_uuid of object
- sql_conds += ["#{sql_table}.uuid in (SELECT target_uuid
- FROM permission_view
- WHERE user_uuid in (:user_uuids) and perm_level >= 1 and trashed = (:include_trashed)
- GROUP BY user_uuid, target_uuid)"]
-
- if self.column_names.include? 'owner_uuid'
- # At least read permission from user_uuid to target_uuid that owns object
- sql_conds += ["#{sql_table}.owner_uuid in (SELECT target_uuid
- FROM permission_view
- WHERE user_uuid in (:user_uuids) and
- target_owner_uuid IS NOT NULL and
- perm_level >= 1 and trashed = (:include_trashed)
- GROUP BY user_uuid, target_uuid)"]
+ trashed_check = ""
+ if !include_trash then
+ trashed_check = "AND trashed = 0"
+ end
+
+ # Note: it is possible to combine the direct_check and
+ # owner_check into a single EXISTS() clause, however it turns
+ # out query optimizer doesn't like it and forces a sequential
+ # table scan. Constructing the query with separate EXISTS()
+ # clauses enables it to use the index.
+ #
+ # see issue 13208 for details.
+
+ # Match a direct read permission link from the user to the record uuid
+ direct_check = "EXISTS(SELECT 1 FROM #{PERMISSION_VIEW} "+
+ "WHERE user_uuid IN (:user_uuids) AND perm_level >= 1 #{trashed_check} AND target_uuid = #{sql_table}.uuid)"
+
+ # Match a read permission link from the user to the record's owner_uuid
+ owner_check = ""
+ if sql_table != "api_client_authorizations" and sql_table != "groups" then
+ owner_check = "OR EXISTS(SELECT 1 FROM #{PERMISSION_VIEW} "+
+ "WHERE user_uuid IN (:user_uuids) AND perm_level >= 1 #{trashed_check} AND target_uuid = #{sql_table}.owner_uuid AND target_owner_uuid IS NOT NULL) "