code.gitea.io/gitea@v1.22.3/models/db/sequence.go (about)

     1  // Copyright 2018 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package db
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"regexp"
    10  
    11  	"code.gitea.io/gitea/modules/setting"
    12  )
    13  
    14  // CountBadSequences looks for broken sequences from recreate-table mistakes
    15  func CountBadSequences(_ context.Context) (int64, error) {
    16  	if !setting.Database.Type.IsPostgreSQL() {
    17  		return 0, nil
    18  	}
    19  
    20  	sess := x.NewSession()
    21  	defer sess.Close()
    22  
    23  	var sequences []string
    24  	schema := x.Dialect().URI().Schema
    25  
    26  	sess.Engine().SetSchema("")
    27  	if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__%_id_seq%' AND sequence_catalog = ?", setting.Database.Name).Find(&sequences); err != nil {
    28  		return 0, err
    29  	}
    30  	sess.Engine().SetSchema(schema)
    31  
    32  	return int64(len(sequences)), nil
    33  }
    34  
    35  // FixBadSequences fixes for broken sequences from recreate-table mistakes
    36  func FixBadSequences(_ context.Context) error {
    37  	if !setting.Database.Type.IsPostgreSQL() {
    38  		return nil
    39  	}
    40  
    41  	sess := x.NewSession()
    42  	defer sess.Close()
    43  	if err := sess.Begin(); err != nil {
    44  		return err
    45  	}
    46  
    47  	var sequences []string
    48  	schema := sess.Engine().Dialect().URI().Schema
    49  
    50  	sess.Engine().SetSchema("")
    51  	if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__%_id_seq%' AND sequence_catalog = ?", setting.Database.Name).Find(&sequences); err != nil {
    52  		return err
    53  	}
    54  	sess.Engine().SetSchema(schema)
    55  
    56  	sequenceRegexp := regexp.MustCompile(`tmp_recreate__(\w+)_id_seq.*`)
    57  
    58  	for _, sequence := range sequences {
    59  		tableName := sequenceRegexp.FindStringSubmatch(sequence)[1]
    60  		newSequenceName := tableName + "_id_seq"
    61  		if _, err := sess.Exec(fmt.Sprintf("ALTER SEQUENCE `%s` RENAME TO `%s`", sequence, newSequenceName)); err != nil {
    62  			return err
    63  		}
    64  		if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', COALESCE((SELECT MAX(id)+1 FROM `%s`), 1), false)", newSequenceName, tableName)); err != nil {
    65  			return err
    66  		}
    67  	}
    68  
    69  	return sess.Commit()
    70  }