diff --git a/server/services/store/mattermostauthlayer/mattermostauthlayer.go b/server/services/store/mattermostauthlayer/mattermostauthlayer.go index 65d3b28d5..613964121 100644 --- a/server/services/store/mattermostauthlayer/mattermostauthlayer.go +++ b/server/services/store/mattermostauthlayer/mattermostauthlayer.go @@ -671,6 +671,11 @@ func (s *MattermostAuthLayer) baseUserQuery(showEmail, showName bool) sq.SelectB // they're open, regardless of the user membership. // Search is case-insensitive. func (s *MattermostAuthLayer) SearchBoardsForUser(term, userID string, includePublicBoards bool) ([]*model.Board, error) { + // as we're joining three queries, we need to avoid numbered + // placeholders until the join is done, so we use the default + // question mark placeholder here + builder := s.getQueryBuilder().PlaceholderFormat(sq.Question) + var boardMembersWhere sq.Or var channelMembersWhere sq.Or @@ -692,7 +697,7 @@ func (s *MattermostAuthLayer) SearchBoardsForUser(term, userID string, includePu } } - boardMembersQ := s.getQueryBuilder(). + boardMembersQ := builder. Select(boardFields("b.")...). From(s.tablePrefix + "boards as b"). Join(s.tablePrefix + "board_members as bm on b.id=bm.board_id"). @@ -701,7 +706,7 @@ func (s *MattermostAuthLayer) SearchBoardsForUser(term, userID string, includePu }). Where(boardMembersWhere) - teamMembersQ := s.getQueryBuilder(). + teamMembersQ := builder. Select(boardFields("b.")...). From(s.tablePrefix + "boards as b"). Join("TeamMembers as tm on tm.teamid=b.team_id"). @@ -711,7 +716,7 @@ func (s *MattermostAuthLayer) SearchBoardsForUser(term, userID string, includePu "tm.deleteAt": 0, }) - channelMembersQ := s.getQueryBuilder(). + channelMembersQ := builder. Select(boardFields("b.")...). From(s.tablePrefix + "boards as b"). Join("ChannelMembers as cm on cm.channelId=b.channel_id"). @@ -774,7 +779,23 @@ func (s *MattermostAuthLayer) SearchBoardsForUser(term, userID string, includePu unionQ = unionQ.Where(sq.Eq{"b.id": boardIDs}) } - rows, err := unionQ.Query() + unionSQL, unionArgs, err := unionQ.ToSql() + if err != nil { + return nil, fmt.Errorf("SearchBoardsForUser error getting unionSQL: %w", err) + } + + // if we're using postgres or sqlite, we need to replace the + // question mark placeholder with the numbered dollar one, now + // that the full query is built + if s.dbType == model.PostgresDBType || s.dbType == model.SqliteDBType { + var rErr error + unionSQL, rErr = sq.Dollar.ReplacePlaceholders(unionSQL) + if rErr != nil { + return nil, fmt.Errorf("SearchBoardsForUser unable to replace unionSQL placeholders: %w", rErr) + } + } + + rows, err := s.mmDB.Query(unionSQL, unionArgs...) if err != nil { s.logger.Error(`searchBoardsForUser ERROR`, mlog.Err(err)) return nil, err @@ -789,7 +810,12 @@ func (s *MattermostAuthLayer) SearchBoardsForUser(term, userID string, includePu // they're open, regardless of the user membership. // Search is case-insensitive. func (s *MattermostAuthLayer) SearchBoardsForUserInTeam(teamID, term, userID string) ([]*model.Board, error) { - openBoardsQ := s.getQueryBuilder(). + // as we're joining three queries, we need to avoid numbered + // placeholders until the join is done, so we use the default + // question mark placeholder here + builder := s.getQueryBuilder().PlaceholderFormat(sq.Question) + + openBoardsQ := builder. Select(boardFields("b.")...). From(s.tablePrefix + "boards as b"). Where(sq.Eq{ @@ -798,7 +824,7 @@ func (s *MattermostAuthLayer) SearchBoardsForUserInTeam(teamID, term, userID str "b.type": model.BoardTypeOpen, }) - memberBoardsQ := s.getQueryBuilder(). + memberBoardsQ := builder. Select(boardFields("b.")...). From(s.tablePrefix + "boards AS b"). Join(s.tablePrefix + "board_members AS bm on b.id = bm.board_id"). @@ -808,7 +834,7 @@ func (s *MattermostAuthLayer) SearchBoardsForUserInTeam(teamID, term, userID str "bm.user_id": userID, }) - channelMemberBoardsQ := s.getQueryBuilder(). + channelMemberBoardsQ := builder. Select(boardFields("b.")...). From(s.tablePrefix + "boards AS b"). Join("ChannelMembers AS cm on cm.channelId = b.channel_id"). @@ -838,14 +864,12 @@ func (s *MattermostAuthLayer) SearchBoardsForUserInTeam(teamID, term, userID str memberBoardsSQL, memberBoardsArgs, err := memberBoardsQ.ToSql() if err != nil { - s.logger.Error(`searchBoardsForUser ERROR getting memberBoardsSQL`, mlog.Err(err)) - return nil, err + return nil, fmt.Errorf("SearchBoardsForUserInTeam error getting memberBoardsSQL: %w", err) } channelMemberBoardsSQL, channelMemberBoardsArgs, err := channelMemberBoardsQ.ToSql() if err != nil { - s.logger.Error(`searchBoardsForUser ERROR getting channelMemberBoardsSQL`, mlog.Err(err)) - return nil, err + return nil, fmt.Errorf("SearchBoardsForUserInTeam error getting channelMemberBoardsSQL: %w", err) } unionQ := openBoardsQ. @@ -853,9 +877,25 @@ func (s *MattermostAuthLayer) SearchBoardsForUserInTeam(teamID, term, userID str Suffix(") UNION ("+memberBoardsSQL, memberBoardsArgs...). Suffix(") UNION ("+channelMemberBoardsSQL+")", channelMemberBoardsArgs...) - rows, err := unionQ.Query() + unionSQL, unionArgs, err := unionQ.ToSql() if err != nil { - s.logger.Error(`searchBoardsForUser ERROR`, mlog.Err(err)) + return nil, fmt.Errorf("SearchBoardsForUserInTeam error getting unionSQL: %w", err) + } + + // if we're using postgres or sqlite, we need to replace the + // question mark placeholder with the numbered dollar one, now + // that the full query is built + if s.dbType == model.PostgresDBType || s.dbType == model.SqliteDBType { + var rErr error + unionSQL, rErr = sq.Dollar.ReplacePlaceholders(unionSQL) + if rErr != nil { + return nil, fmt.Errorf("SearchBoardsForUserInTeam unable to replace unionSQL placeholders: %w", rErr) + } + } + + rows, err := s.mmDB.Query(unionSQL, unionArgs...) + if err != nil { + s.logger.Error(`searchBoardsForUserInTeam ERROR`, mlog.Err(err)) return nil, err } defer s.CloseRows(rows)