package postgres

import (
	
	
	
	

	
	
	
	
	
)

const indexSql = `
select
    t.relname as table_name,
    i.relname as index_name,
    a.attname as column_name,
    ix.indisunique as non_unique,
	ix.indisprimary as primary
from
    pg_class t,
    pg_class i,
    pg_index ix,
    pg_attribute a
where
    t.oid = ix.indrelid
    and i.oid = ix.indexrelid
    and a.attrelid = t.oid
    and a.attnum = ANY(ix.indkey)
    and t.relkind = 'r'
    and t.relname = ?
`

var typeAliasMap = map[string][]string{
	"int2":                     {"smallint"},
	"int4":                     {"integer"},
	"int8":                     {"bigint"},
	"smallint":                 {"int2"},
	"integer":                  {"int4"},
	"bigint":                   {"int8"},
	"decimal":                  {"numeric"},
	"numeric":                  {"decimal"},
	"timestamptz":              {"timestamp with time zone"},
	"timestamp with time zone": {"timestamptz"},
}

type Migrator struct {
	migrator.Migrator
}

func ( Migrator) () ( string) {
	.DB.Raw("SELECT CURRENT_DATABASE()").Scan(&)
	return
}

func ( Migrator) ( []schema.IndexOption,  *gorm.Statement) ( []interface{}) {
	for ,  := range  {
		 := .Quote(.DBName)
		if .Expression != "" {
			 = .Expression
		}

		if .Collate != "" {
			 += " COLLATE " + .Collate
		}

		if .Sort != "" {
			 += " " + .Sort
		}
		 = append(, clause.Expr{SQL: })
	}
	return
}

func ( Migrator) ( interface{},  string) bool {
	var  int64
	.RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookIndex();  != nil {
				 = .Name
			}
		}
		,  := .CurrentSchema(, .Table)
		return .DB.Raw(
			"SELECT count(*) FROM pg_indexes WHERE tablename = ? AND indexname = ? AND schemaname = ?", , , ,
		).Scan(&).Error
	})

	return  > 0
}

func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookIndex();  != nil {
				 := .BuildIndexOptions(.Fields, )
				 := []interface{}{clause.Column{Name: .Name}, .CurrentTable(), }

				 := "CREATE "
				if .Class != "" {
					 += .Class + " "
				}
				 += "INDEX "

				if strings.TrimSpace(strings.ToUpper(.Option)) == "CONCURRENTLY" {
					 += "CONCURRENTLY "
				}

				 += "IF NOT EXISTS ? ON ?"

				if .Type != "" {
					 += " USING " + .Type + "(?)"
				} else {
					 += " ?"
				}

				if .Where != "" {
					 += " WHERE " + .Where
				}

				return .DB.Exec(, ...).Error
			}
		}

		return fmt.Errorf("failed to create index with name %v", )
	})
}

func ( Migrator) ( interface{}, ,  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		return .DB.Exec(
			"ALTER INDEX ? RENAME TO ?",
			clause.Column{Name: }, clause.Column{Name: },
		).Error
	})
}

func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookIndex();  != nil {
				 = .Name
			}
		}

		return .DB.Exec("DROP INDEX ?", clause.Column{Name: }).Error
	})
}

func ( Migrator) () ( []string,  error) {
	,  := .CurrentSchema(.DB.Statement, "")
	return , .DB.Raw("SELECT table_name FROM information_schema.tables WHERE table_schema = ? AND table_type = ?", , "BASE TABLE").Scan(&).Error
}

func ( Migrator) ( ...interface{}) ( error) {
	if  = .Migrator.CreateTable(...);  != nil {
		return
	}
	for ,  := range .ReorderModels(, false) {
		if  = .RunWithValue(, func( *gorm.Statement) error {
			if .Schema != nil {
				for ,  := range .Schema.DBNames {
					 := .Schema.FieldsByDBName[]
					if .Comment != "" {
						if  := .DB.Exec(
							"COMMENT ON COLUMN ?.? IS ?",
							.CurrentTable(), clause.Column{Name: .DBName}, gorm.Expr(.Migrator.Dialector.Explain("$1", .Comment)),
						).Error;  != nil {
							return 
						}
					}
				}
			}
			return nil
		});  != nil {
			return
		}
	}
	return
}

func ( Migrator) ( interface{}) bool {
	var  int64
	.RunWithValue(, func( *gorm.Statement) error {
		,  := .CurrentSchema(, .Table)
		return .DB.Raw("SELECT count(*) FROM information_schema.tables WHERE table_schema = ? AND table_name = ? AND table_type = ?", , , "BASE TABLE").Scan(&).Error
	})
	return  > 0
}

func ( Migrator) ( ...interface{}) error {
	 = .ReorderModels(, false)
	 := .DB.Session(&gorm.Session{})
	for  := len() - 1;  >= 0; -- {
		if  := .RunWithValue([], func( *gorm.Statement) error {
			return .Exec("DROP TABLE IF EXISTS ? CASCADE", .CurrentTable()).Error
		});  != nil {
			return 
		}
	}
	return nil
}

func ( Migrator) ( interface{},  string) error {
	if  := .Migrator.AddColumn(, );  != nil {
		return 
	}
	.resetPreparedStmts()

	return .RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookUpField();  != nil {
				if .Comment != "" {
					if  := .DB.Exec(
						"COMMENT ON COLUMN ?.? IS ?",
						.CurrentTable(), clause.Column{Name: .DBName}, gorm.Expr(.Migrator.Dialector.Explain("$1", .Comment)),
					).Error;  != nil {
						return 
					}
				}
			}
		}
		return nil
	})
}

func ( Migrator) ( interface{},  string) bool {
	var  int64
	.RunWithValue(, func( *gorm.Statement) error {
		 := 
		if .Schema != nil {
			if  := .Schema.LookUpField();  != nil {
				 = .DBName
			}
		}

		,  := .CurrentSchema(, .Table)
		return .DB.Raw(
			"SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_schema = ? AND table_name = ? AND column_name = ?",
			, , ,
		).Scan(&).Error
	})

	return  > 0
}

func ( Migrator) ( interface{},  *schema.Field,  gorm.ColumnType) error {
	// skip primary field
	if !.PrimaryKey {
		if  := .Migrator.MigrateColumn(, , );  != nil {
			return 
		}
	}

	return .RunWithValue(, func( *gorm.Statement) error {
		var  string
		,  := .CurrentSchema(, .Table)
		 := []interface{}{, , .DBName, .Table, }
		 := "SELECT description FROM pg_catalog.pg_description "
		 += "WHERE objsubid = (SELECT ordinal_position FROM information_schema.columns WHERE table_schema = ? AND table_name = ? AND column_name = ?) "
		 += "AND objoid = (SELECT oid FROM pg_catalog.pg_class WHERE relname = ? AND relnamespace = "
		 += "(SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = ?))"
		.DB.Raw(, ...).Scan(&)

		 := strings.Trim(.Comment, "'")
		 = strings.Trim(, `"`)
		if .Comment != "" &&  !=  {
			if  := .DB.Exec(
				"COMMENT ON COLUMN ?.? IS ?",
				.CurrentTable(), clause.Column{Name: .DBName}, gorm.Expr(.Migrator.Dialector.Explain("$1", .Comment)),
			).Error;  != nil {
				return 
			}
		}
		return nil
	})
}

// AlterColumn alter value's `field` column' type based on schema definition
func ( Migrator) ( interface{},  string) error {
	 := .RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookUpField();  != nil {
				var (
					,   = .DB.Migrator().ColumnTypes()
					 *migrator.ColumnType
				)
				for ,  := range  {
					if .Name() == .DBName {
						, _ = .(*migrator.ColumnType)
					}
				}

				 := clause.Expr{SQL: .DataTypeOf()}
				// check for typeName and SQL name
				 := true
				if .DatabaseTypeName() != .SQL {
					 = false
					// if different, also check for aliases
					 := .GetTypeAliases(.DatabaseTypeName())
					for ,  := range  {
						if strings.HasPrefix(.SQL, ) {
							 = true
							break
						}
					}
				}

				// not same, migrate
				if ! {
					,  := .AutoIncrement()
					if .AutoIncrement &&  { // update
						,  := getSerialDatabaseType(.SQL)
						if ,  := .ColumnType();  !=  {
							if  := .UpdateSequence(.DB, , , );  != nil {
								return 
							}
						}
					} else if .AutoIncrement && ! { // create
						,  := getSerialDatabaseType(.SQL)
						if  := .CreateSequence(.DB, , , );  != nil {
							return 
						}
					} else if !.AutoIncrement &&  { // delete
						if  := .DeleteSequence(.DB, , , );  != nil {
							return 
						}
					} else {
						if  := .modifyColumn(, , , );  != nil {
							return 
						}
					}
				}

				if ,  := .Nullable();  == .NotNull {
					if .NotNull {
						if  := .DB.Exec("ALTER TABLE ? ALTER COLUMN ? SET NOT NULL", .CurrentTable(), clause.Column{Name: .DBName}).Error;  != nil {
							return 
						}
					} else {
						if  := .DB.Exec("ALTER TABLE ? ALTER COLUMN ? DROP NOT NULL", .CurrentTable(), clause.Column{Name: .DBName}).Error;  != nil {
							return 
						}
					}
				}

				if ,  := .Unique(); ! && .Unique {
					 := clause.Column{Name: .DB.Config.NamingStrategy.IndexName(.Table, .DBName)}
					// Not a unique constraint but a unique index
					if !.HasIndex(.Table, .Name) {
						if  := .DB.Exec("ALTER TABLE ? ADD CONSTRAINT ? UNIQUE(?)", .CurrentTable(), , clause.Column{Name: .DBName}).Error;  != nil {
							return 
						}
					}
				}

				if ,  := .DefaultValue(); (.DefaultValueInterface == nil && ) ||  != .DefaultValue {
					if .HasDefaultValue && (.DefaultValueInterface != nil || .DefaultValue != "") {
						if .DefaultValueInterface != nil {
							 := &gorm.Statement{Vars: []interface{}{.DefaultValueInterface}}
							.Dialector.BindVarTo(, , .DefaultValueInterface)
							if  := .DB.Exec("ALTER TABLE ? ALTER COLUMN ? SET DEFAULT ?", .CurrentTable(), clause.Column{Name: .DBName}, clause.Expr{SQL: .Dialector.Explain(.SQL.String(), .DefaultValueInterface)}).Error;  != nil {
								return 
							}
						} else if .DefaultValue != "(-)" {
							if  := .DB.Exec("ALTER TABLE ? ALTER COLUMN ? SET DEFAULT ?", .CurrentTable(), clause.Column{Name: .DBName}, clause.Expr{SQL: .DefaultValue}).Error;  != nil {
								return 
							}
						} else {
							if  := .DB.Exec("ALTER TABLE ? ALTER COLUMN ? DROP DEFAULT", .CurrentTable(), clause.Column{Name: .DBName}, clause.Expr{SQL: .DefaultValue}).Error;  != nil {
								return 
							}
						}
					}
				}
				return nil
			}
		}
		return fmt.Errorf("failed to look up field with name: %s", )
	})

	if  != nil {
		return 
	}
	.resetPreparedStmts()
	return nil
}

func ( Migrator) ( *gorm.Statement,  *schema.Field,  clause.Expr,  *migrator.ColumnType) error {
	 := "ALTER TABLE ? ALTER COLUMN ? TYPE ? USING ?::?"
	 := false

	if .SQL == "boolean" {
		switch .DatabaseTypeName() {
		case "int2", "int8", "numeric":
			 = "ALTER TABLE ? ALTER COLUMN ? TYPE ? USING ?::int::?"
		}
		 = true
	}

	if ,  := .DefaultValue();  != "" &&  {
		if  := .DB.Exec("ALTER TABLE ? ALTER COLUMN ? DROP DEFAULT", .CurrentTable(), clause.Column{Name: .DBName}).Error;  != nil {
			return 
		}
	}
	if  := .DB.Exec(, .CurrentTable(), clause.Column{Name: .DBName}, , clause.Column{Name: .DBName}, ).Error;  != nil {
		return 
	}
	return nil
}

func ( Migrator) ( interface{},  string) bool {
	var  int64
	.RunWithValue(, func( *gorm.Statement) error {
		, ,  := .GuessConstraintAndTable(, )
		,  := .CurrentSchema(, )
		if  != nil {
			 = .Name
		} else if  != nil {
			 = .Name
		}

		return .DB.Raw(
			"SELECT count(*) FROM INFORMATION_SCHEMA.table_constraints WHERE table_schema = ? AND table_name = ? AND constraint_name = ?",
			, , ,
		).Scan(&).Error
	})

	return  > 0
}

func ( Migrator) ( interface{}) ( []gorm.ColumnType,  error) {
	 = make([]gorm.ColumnType, 0)
	 = .RunWithValue(, func( *gorm.Statement) error {
		var (
			      = .DB.Migrator().CurrentDatabase()
			,  = .CurrentSchema(, .Table)
			,          = .DB.Raw(
				"SELECT c.column_name, c.is_nullable = 'YES', c.udt_name, c.character_maximum_length, c.numeric_precision, c.numeric_precision_radix, c.numeric_scale, c.datetime_precision, 8 * typlen, c.column_default, pd.description, c.identity_increment FROM information_schema.columns AS c JOIN pg_type AS pgt ON c.udt_name = pgt.typname LEFT JOIN pg_catalog.pg_description as pd ON pd.objsubid = c.ordinal_position AND pd.objoid = (SELECT oid FROM pg_catalog.pg_class WHERE relname = c.table_name AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = c.table_schema)) where table_catalog = ? AND table_schema = ? AND table_name = ?",
				, , ).Rows()
		)

		if  != nil {
			return 
		}

		for .Next() {
			var (
				 = &migrator.ColumnType{
					PrimaryKeyValue: sql.NullBool{Valid: true},
					UniqueValue:     sql.NullBool{Valid: true},
				}
				 sql.NullInt64
				        sql.NullInt64
				      sql.NullInt64
				 sql.NullString
			)

			 = .Scan(
				&.NameValue, &.NullableValue, &.DataTypeValue, &.LengthValue, &.DecimalSizeValue,
				&, &.ScaleValue, &, &, &.DefaultValueValue, &.CommentValue, &,
			)
			if  != nil {
				return 
			}

			if .Valid && .Int64 > 0 {
				.LengthValue = 
			}

			if (strings.HasPrefix(.DefaultValueValue.String, "nextval('") &&
				strings.HasSuffix(.DefaultValueValue.String, "seq'::regclass)")) || (.Valid && .String != "") {
				.AutoIncrementValue = sql.NullBool{Bool: true, Valid: true}
				.DefaultValueValue = sql.NullString{}
			}

			if .DefaultValueValue.Valid {
				.DefaultValueValue.String = parseDefaultValueValue(.DefaultValueValue.String)
			}

			if .Valid {
				.DecimalSizeValue = 
			}

			 = append(, )
		}
		.Close()

		// assign sql column type
		{
			,  := .GetRows(, )
			if  != nil {
				return 
			}
			,  := .ColumnTypes()
			if  != nil {
				return 
			}
			for ,  := range  {
				for ,  := range  {
					if .Name() == .Name() {
						.(*migrator.ColumnType).SQLColumnType = 
						break
					}
				}
			}
			.Close()
		}

		// check primary, unique field
		{
			,  := .DB.Raw("SELECT constraint_name FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_catalog, table_name, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = ? AND c.table_schema = ? AND c.table_name = ? AND constraint_type = ?", , , , "UNIQUE").Rows()
			if  != nil {
				return 
			}
			 := map[string]int{}
			for .Next() {
				var  string
				.Scan(&)
				[]++
			}
			.Close()

			,  = .DB.Raw("SELECT c.column_name, constraint_name, constraint_type FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_catalog, table_name, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = ? AND c.table_schema = ? AND c.table_name = ?", , , ).Rows()
			if  != nil {
				return 
			}
			for .Next() {
				var , ,  string
				.Scan(&, &, &)
				for ,  := range  {
					 := .(*migrator.ColumnType)
					if .NameValue.String ==  {
						switch  {
						case "PRIMARY KEY":
							.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true}
						case "UNIQUE":
							if [] == 1 {
								.UniqueValue = sql.NullBool{Bool: true, Valid: true}
							}
						}
						break
					}
				}
			}
			.Close()
		}

		// check column type
		{
			,  := .DB.Raw(`SELECT a.attname as column_name, format_type(a.atttypid, a.atttypmod) AS data_type
		FROM pg_attribute a JOIN pg_class b ON a.attrelid = b.oid AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = ?)
		WHERE a.attnum > 0 -- hide internal columns
		AND NOT a.attisdropped -- hide deleted columns
		AND b.relname = ?`, , ).Rows()
			if  != nil {
				return 
			}

			for .Next() {
				var ,  string
				.Scan(&, &)
				for ,  := range  {
					 := .(*migrator.ColumnType)
					if .NameValue.String ==  {
						.ColumnTypeValue = sql.NullString{String: , Valid: true}
						// Handle array type: _text -> text[] , _int4 -> integer[]
						// Not support array size limits and array size limits because:
						// https://www.postgresql.org/docs/current/arrays.html#ARRAYS-DECLARATION
						if strings.HasPrefix(.DataTypeValue.String, "_") {
							.DataTypeValue = sql.NullString{String: , Valid: true}
						}
						break
					}
				}
			}
			.Close()
		}

		return 
	})
	return
}

func ( Migrator) ( interface{},  interface{}) (*sql.Rows, error) {
	 := .(string)
	if ,  := .(string);  {
		 = fmt.Sprintf("%v.%v", , )
	}

	return .DB.Session(&gorm.Session{}).Table().Limit(1).Scopes(func( *gorm.DB) *gorm.DB {
		,  := .Dialector.(Dialector)
		// use simple protocol
		if !.DB.PrepareStmt && (.Config != nil && (.Config.DriverName == "" || .Config.DriverName == "pgx")) {
			.Statement.Vars = append([]interface{}{pgx.QueryExecModeSimpleProtocol}, .Statement.Vars...)
		}
		return 
	}).Rows()
}

func ( Migrator) ( *gorm.Statement,  string) (interface{}, interface{}) {
	if strings.Contains(, ".") {
		if  := strings.Split(, `.`); len() == 2 {
			return [0], [1]
		}
	}

	if .TableExpr != nil {
		if  := strings.Split(.TableExpr.SQL, `"."`); len() == 2 {
			return strings.TrimPrefix([0], `"`), 
		}
	}
	return clause.Expr{SQL: "CURRENT_SCHEMA()"}, 
}

func ( Migrator) ( *gorm.DB,  *gorm.Statement,  *schema.Field,
	 string) ( error) {

	,  := .CurrentSchema(, .Table)
	 := .(string)

	 := strings.Join([]string{, .DBName, "seq"}, "_")
	if  = .Exec(`CREATE SEQUENCE IF NOT EXISTS ? AS ?`, clause.Expr{SQL: },
		clause.Expr{SQL: }).Error;  != nil {
		return 
	}

	if  := .Exec("ALTER TABLE ? ALTER COLUMN ? SET DEFAULT nextval('?')",
		clause.Expr{SQL: }, clause.Expr{SQL: .DBName}, clause.Expr{SQL: }).Error;  != nil {
		return 
	}

	if  := .Exec("ALTER SEQUENCE ? OWNED BY ?.?",
		clause.Expr{SQL: }, clause.Expr{SQL: }, clause.Expr{SQL: .DBName}).Error;  != nil {
		return 
	}
	return
}

func ( Migrator) ( *gorm.DB,  *gorm.Statement,  *schema.Field,
	 string) ( error) {

	,  := .getColumnSequenceName(, , )
	if  != nil {
		return 
	}

	if  = .Exec(`ALTER SEQUENCE IF EXISTS ? AS ?`, clause.Expr{SQL: }, clause.Expr{SQL: }).Error;  != nil {
		return 
	}

	if  := .Exec("ALTER TABLE ? ALTER COLUMN ? TYPE ?",
		.CurrentTable(), clause.Expr{SQL: .DBName}, clause.Expr{SQL: }).Error;  != nil {
		return 
	}
	return
}

func ( Migrator) ( *gorm.DB,  *gorm.Statement,  *schema.Field,
	 clause.Expr) ( error) {

	,  := .getColumnSequenceName(, , )
	if  != nil {
		return 
	}

	if  := .Exec("ALTER TABLE ? ALTER COLUMN ? TYPE ?", .CurrentTable(), clause.Column{Name: .DBName}, ).Error;  != nil {
		return 
	}

	if  := .Exec("ALTER TABLE ? ALTER COLUMN ? DROP DEFAULT",
		.CurrentTable(), clause.Expr{SQL: .DBName}).Error;  != nil {
		return 
	}

	if  = .Exec(`DROP SEQUENCE IF EXISTS ?`, clause.Expr{SQL: }).Error;  != nil {
		return 
	}

	return
}

func ( Migrator) ( *gorm.DB,  *gorm.Statement,  *schema.Field) (
	 string,  error) {
	,  := .CurrentSchema(, .Table)

	// DefaultValueValue is reset by ColumnTypes, search again.
	var  string
	 = .Raw(
		`SELECT column_default FROM information_schema.columns WHERE table_name = ? AND column_name = ?`,
		, .DBName).Scan(&).Error

	if  != nil {
		return
	}

	 = strings.TrimSuffix(
		strings.TrimPrefix(, `nextval('`),
		`'::regclass)`,
	)
	return
}

func ( Migrator) ( interface{}) ([]gorm.Index, error) {
	 := make([]gorm.Index, 0)

	 := .RunWithValue(, func( *gorm.Statement) error {
		 := make([]*Index, 0)
		 := .DB.Raw(indexSql, .Table).Scan(&).Error
		if  != nil {
			return 
		}
		 := groupByIndexName()
		for ,  := range  {
			 := &migrator.Index{
				TableName: [0].TableName,
				NameValue: [0].IndexName,
				PrimaryKeyValue: sql.NullBool{
					Bool:  [0].Primary,
					Valid: true,
				},
				UniqueValue: sql.NullBool{
					Bool:  [0].NonUnique,
					Valid: true,
				},
			}
			for ,  := range  {
				.ColumnList = append(.ColumnList, .ColumnName)
			}
			 = append(, )
		}
		return nil
	})
	return , 
}

// Index table index info
type Index struct {
	TableName  string `gorm:"column:table_name"`
	ColumnName string `gorm:"column:column_name"`
	IndexName  string `gorm:"column:index_name"`
	NonUnique  bool   `gorm:"column:non_unique"`
	Primary    bool   `gorm:"column:primary"`
}

func groupByIndexName( []*Index) map[string][]*Index {
	 := make(map[string][]*Index, len())
	for ,  := range  {
		[.IndexName] = append([.IndexName], )
	}
	return 
}

func ( Migrator) ( string) []string {
	return typeAliasMap[]
}

// should reset prepared stmts when table changed
func ( Migrator) () {
	if .DB.PrepareStmt {
		if ,  := .DB.ConnPool.(*gorm.PreparedStmtDB);  {
			.Reset()
		}
	}
}

func ( Migrator) ( interface{},  string) error {
	if  := .Migrator.DropColumn(, );  != nil {
		return 
	}

	.resetPreparedStmts()
	return nil
}

func ( Migrator) ( interface{}, ,  string) error {
	if  := .Migrator.RenameColumn(, , );  != nil {
		return 
	}

	.resetPreparedStmts()
	return nil
}

func parseDefaultValueValue( string) string {
	 := regexp.MustCompile(`^(.*?)(?:::.*)?$`).ReplaceAllString(, "$1")
	return strings.Trim(, "'")
}