code.gitea.io/gitea@v1.21.7/models/migrations/v1_14/v158.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package v1_14 //nolint
     5  
     6  import (
     7  	"fmt"
     8  	"strconv"
     9  
    10  	"code.gitea.io/gitea/modules/log"
    11  	"code.gitea.io/gitea/modules/setting"
    12  
    13  	"xorm.io/xorm"
    14  )
    15  
    16  func UpdateCodeCommentReplies(x *xorm.Engine) error {
    17  	type Comment struct {
    18  		ID          int64  `xorm:"pk autoincr"`
    19  		CommitSHA   string `xorm:"VARCHAR(40)"`
    20  		Patch       string `xorm:"TEXT patch"`
    21  		Invalidated bool
    22  
    23  		// Not extracted but used in the below query
    24  		Type     int   `xorm:"INDEX"`
    25  		Line     int64 // - previous line / + proposed line
    26  		TreePath string
    27  		ReviewID int64 `xorm:"index"`
    28  	}
    29  
    30  	if err := x.Sync(new(Comment)); err != nil {
    31  		return err
    32  	}
    33  
    34  	sqlSelect := `SELECT comment.id as id, first.commit_sha as commit_sha, first.patch as patch, first.invalidated as invalidated`
    35  	sqlTail := ` FROM comment INNER JOIN (
    36  		SELECT C.id, C.review_id, C.line, C.tree_path, C.patch, C.commit_sha, C.invalidated
    37  		FROM comment AS C
    38  		WHERE C.type = 21
    39  			AND C.created_unix =
    40  				(SELECT MIN(comment.created_unix)
    41  					FROM comment
    42  					WHERE comment.review_id = C.review_id
    43  					AND comment.type = 21
    44  					AND comment.line = C.line
    45  					AND comment.tree_path = C.tree_path)
    46  		) AS first
    47  		ON comment.review_id = first.review_id
    48  			AND comment.tree_path = first.tree_path AND comment.line = first.line
    49  	WHERE comment.type = 21
    50  		AND comment.id != first.id
    51  		AND comment.commit_sha != first.commit_sha`
    52  
    53  	var (
    54  		sqlCmd    string
    55  		start     = 0
    56  		batchSize = 100
    57  		sess      = x.NewSession()
    58  	)
    59  	defer sess.Close()
    60  	for {
    61  		if err := sess.Begin(); err != nil {
    62  			return err
    63  		}
    64  
    65  		if setting.Database.Type.IsMSSQL() {
    66  			if _, err := sess.Exec(sqlSelect + " INTO #temp_comments" + sqlTail); err != nil {
    67  				log.Error("unable to create temporary table")
    68  				return err
    69  			}
    70  		}
    71  
    72  		comments := make([]*Comment, 0, batchSize)
    73  
    74  		switch {
    75  		case setting.Database.Type.IsMySQL():
    76  			sqlCmd = sqlSelect + sqlTail + " LIMIT " + strconv.Itoa(batchSize) + ", " + strconv.Itoa(start)
    77  		case setting.Database.Type.IsPostgreSQL():
    78  			fallthrough
    79  		case setting.Database.Type.IsSQLite3():
    80  			sqlCmd = sqlSelect + sqlTail + " LIMIT " + strconv.Itoa(batchSize) + " OFFSET " + strconv.Itoa(start)
    81  		case setting.Database.Type.IsMSSQL():
    82  			sqlCmd = "SELECT TOP " + strconv.Itoa(batchSize) + " * FROM #temp_comments WHERE " +
    83  				"(id NOT IN ( SELECT TOP " + strconv.Itoa(start) + " id FROM #temp_comments ORDER BY id )) ORDER BY id"
    84  		default:
    85  			return fmt.Errorf("Unsupported database type")
    86  		}
    87  
    88  		if err := sess.SQL(sqlCmd).Find(&comments); err != nil {
    89  			log.Error("failed to select: %v", err)
    90  			return err
    91  		}
    92  
    93  		for _, comment := range comments {
    94  			if _, err := sess.Table("comment").ID(comment.ID).Cols("commit_sha", "patch", "invalidated").Update(comment); err != nil {
    95  				log.Error("failed to update comment[%d]: %v %v", comment.ID, comment, err)
    96  				return err
    97  			}
    98  		}
    99  
   100  		start += len(comments)
   101  
   102  		if err := sess.Commit(); err != nil {
   103  			return err
   104  		}
   105  		if len(comments) < batchSize {
   106  			break
   107  		}
   108  	}
   109  
   110  	return nil
   111  }