1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-18 11:46:23 -07:00

Move filter migration out of common

This commit is contained in:
Eggbertx 2024-10-13 20:30:38 -07:00
parent eb06047055
commit 8d98bc39df
11 changed files with 478 additions and 569 deletions

View file

@ -1,326 +0,0 @@
package common
import (
"context"
"database/sql"
"errors"
"fmt"
"os"
"strings"
"time"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
)
// AddFilterTables is used for the db version 4 upgrade to create the filter tables from the respective SQL init file
func AddFilterTables(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *config.SQLConfig) error {
filePath, err := getInitFilePath("initdb_" + sqlConfig.DBtype + ".sql")
if err != nil {
return err
}
ba, err := os.ReadFile(filePath)
if err != nil {
return err
}
sqlStr := commentRemover.ReplaceAllString(string(ba), " ")
sqlArr := strings.Split(sqlStr, ";")
for _, stmtStr := range sqlArr {
stmtStr = strings.TrimSpace(stmtStr)
if !strings.HasPrefix(stmtStr, "CREATE TABLE DBPREFIXfilter") {
continue
}
if _, err = db.ExecContextSQL(ctx, tx, stmtStr); err != nil {
return err
}
}
return nil
}
// MigrateFileBans migrates file checksum and image fingerprint bans to the filter table
func MigrateFileBans(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, cfg *config.SQLConfig) error {
fileBanTableExists, err := TableExists(ctx, db, tx, "DBPREFIXfilename_ban", cfg)
if err != nil {
return err
}
if !fileBanTableExists {
// no filename bans to migrate (database partially migrated?)
return nil
}
rows, err := db.QueryContextSQL(ctx, tx, `SELECT board_id,staff_id,staff_note,issued_at,checksum,fingerprinter,ban_ip,ban_ip_message FROM DBPREFIXfile_ban`)
if err != nil {
return err
}
defer rows.Close()
var fBanBoardID *int
var fBanStaffID int
var fBanStaffNote string
var fBanIssuedAt time.Time
var fBanChecksum string
var fBanFingerprinter *string
var fBanBanIP bool
var fBanBanIPMessage *string
var matchAction string
var detail string
var filterID int
var field string
for rows.Next() {
if err = rows.Scan(
&fBanBoardID, &fBanStaffID, &fBanStaffNote, &fBanIssuedAt, &fBanChecksum, &fBanFingerprinter, &fBanBanIP, &fBanBanIPMessage,
); err != nil {
return err
}
if fBanBanIP {
matchAction = "ban"
} else {
matchAction = "reject"
}
if fBanBanIPMessage == nil {
detail = ""
} else {
detail = *fBanBanIPMessage
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilters(staff_id, staff_note, issued_at, match_action, match_detail, is_active) VALUES(?,?,?,?,?,?)`,
fBanStaffID, fBanStaffNote, fBanIssuedAt, matchAction, detail, true); err != nil {
return err
}
if err = db.QueryRowContextSQL(ctx, tx, `SELECT MAX(id) FROM DBPREFIXfilters`, nil, []any{&filterID}); err != nil {
return err
}
if fBanBoardID != nil {
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilter_boards(filter_id, board_id) VALUES(?,?)`, filterID, *fBanBoardID,
); err != nil {
return err
}
}
if fBanFingerprinter != nil {
field = *fBanFingerprinter
}
if field == "" {
field = "checksum"
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilter_conditions(filter_id,match_mode,search,field) VALUES(?,?,?,?)`, filterID, gcsql.ExactMatch, fBanChecksum, field,
); err != nil {
return err
}
}
return rows.Close()
}
// MigrateFilenameBans migrates filename bans to the filter table
func MigrateFilenameBans(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, cfg *config.SQLConfig) error {
filenameBanTableExists, err := TableExists(ctx, db, tx, "DBPREFIXfilename_ban", cfg)
if err != nil {
return err
}
if !filenameBanTableExists {
// no filename bans to migrate (database partially migrated?)
return nil
}
rows, err := db.QueryContextSQL(ctx, tx, `SELECT board_id,staff_id,staff_note,issued_at,filename,is_regex FROM DBPREFIXfilename_ban`)
if err != nil {
fmt.Println("query error")
return err
}
defer rows.Close()
var fnBanBoardID *int
var fnBanStaffID int
var fnBanStaffNote string
var fnBanIssuedAt time.Time
var fnBanFilename string
var fnBanIsRegex bool
var filterID int
var matchMode gcsql.StringMatchMode
for rows.Next() {
if err = rows.Scan(
&fnBanBoardID, &fnBanStaffID, &fnBanStaffNote, &fnBanIssuedAt, &fnBanFilename, &fnBanIsRegex,
); err != nil {
return err
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilters(staff_id, staff_note, issued_at, match_action, match_detail, is_active) VALUES(?,?,?,?,?,?)`,
fnBanStaffID, fnBanStaffNote, fnBanIssuedAt, "reject", "", true,
); err != nil {
return err
}
if err = db.QueryRowContextSQL(ctx, tx, `SELECT MAX(id) FROM DBPREFIXfilters`, nil, []any{&filterID}); err != nil {
return err
}
if fnBanBoardID != nil {
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilter_boards(filter_id, board_id) VALUES(?,?)`, filterID, *fnBanBoardID,
); err != nil {
return err
}
}
if fnBanIsRegex {
matchMode = gcsql.RegexMatch
} else {
matchMode = gcsql.SubstrMatch
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilter_conditions(filter_id,match_mode,search,field) VALUES(?,?,?,?)`,
filterID, matchMode, fnBanFilename, "filename",
); err != nil {
return err
}
}
return rows.Close()
}
// MigrateUsernameBans migrates poster name bans to the filter table
func MigrateUsernameBans(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, cfg *config.SQLConfig) error {
usernameBanTableExists, err := TableExists(ctx, db, tx, "DBPREFIXusername_ban", cfg)
if err != nil {
return err
}
if !usernameBanTableExists {
// no name bans to migrate (database partially migrated?)
return nil
}
rows, err := db.QueryContextSQL(ctx, tx, `SELECT board_id,staff_id,staff_note,issued_at,username,is_regex FROM DBPREFIXusername_ban`)
if err != nil {
fmt.Println("MigrateUsernameBans rows error")
return err
}
defer rows.Close()
var unBanBoardID *int
var unBanStaffID int
var unBanStaffNote string
var unBanIssuedAt time.Time
var unBanUsername string
var unBanIsRegex bool
var filterID int
var matchMode gcsql.StringMatchMode
for rows.Next() {
if err = rows.Scan(
&unBanBoardID, &unBanStaffID, &unBanStaffNote, &unBanIssuedAt, &unBanUsername, &unBanIsRegex,
); err != nil {
return err
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilters(staff_id, staff_note, issued_at, match_action, match_detail, is_active) VALUES(?,?,?,?,?,?)`,
unBanStaffID, unBanStaffNote, unBanIssuedAt, "reject", "", true,
); err != nil {
return err
}
if err = db.QueryRowContextSQL(ctx, tx, `SELECT MAX(id) FROM DBPREFIXfilters`, nil, []any{&filterID}); err != nil {
return err
}
if unBanBoardID != nil {
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilter_boards(filter_id, board_id) VALUES(?,?)`, filterID, *unBanBoardID,
); err != nil {
return err
}
}
if unBanIsRegex {
matchMode = gcsql.RegexMatch
} else {
matchMode = gcsql.SubstrMatch
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilter_conditions(filter_id,match_mode,search,field) VALUES(?,?,?,?)`,
filterID, matchMode, unBanUsername, "name",
); err != nil {
return err
}
}
return rows.Close()
}
// MigrateWordfilters migrates pre-filter wordfilters to the filter table
func MigrateWordfilters(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *config.SQLConfig) error {
wordfiltersTableExists, err := TableExists(ctx, db, tx, "DBPREFIXwordfilters", sqlConfig)
if err != nil {
return err
}
if !wordfiltersTableExists {
// no wordfilters to migrate (database partially migrated?)
return nil
}
rows, err := db.QueryContextSQL(ctx, tx, `SELECT board_dirs, staff_id, staff_note, issued_at, search, is_regex, change_to FROM DBPREFIXwordfilters`)
if err != nil {
fmt.Println("MigrateWordfilters rows error")
return err
}
defer rows.Close()
var boardDirsPtr *string
var boardDirs []string
var boardID int
var staffID int
var staffNote string
var issuedAt time.Time
var search string
var isRegex bool
var changeTo string
var filterID int
var matchMode gcsql.StringMatchMode
for rows.Next() {
if err = rows.Scan(&boardDirsPtr, &staffID, &staffNote, &issuedAt, &search, &isRegex, &changeTo); err != nil {
return err
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilters(staff_id, staff_note, issued_at, match_action, match_detail, is_active) VALUES(?,?,?,'replace',?,TRUE)`,
staffID, staffNote, issuedAt, changeTo,
); err != nil {
return err
}
if err = db.QueryRowContextSQL(ctx, tx, `SELECT MAX(id) FROM DBPREFIXfilters`, nil, []any{&filterID}); err != nil {
return err
}
if boardDirsPtr != nil {
boardDirs = strings.Split(*boardDirsPtr, ",")
for _, dir := range boardDirs {
if dir == "" || dir == "*" {
// treated as "all boards", but handle this in the loop just in case there's something like "a,*,b"
// if the only value in the string is *, there will be no single board associated with the filter
continue
}
err = db.QueryRowContextSQL(ctx, tx, `SELECT id FROM DBPREFIXboards WHERE dir = ?`, []any{dir}, []any{&boardID})
if errors.Is(err, sql.ErrNoRows) {
// board may have been deleted, skip it and don't return an error
continue
} else if err != nil {
return err
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilter_boards(filter_id,board_id) VALUES(?,?)`, filterID, boardID,
); err != nil {
return err
}
}
}
if isRegex {
matchMode = gcsql.RegexMatch
} else {
matchMode = gcsql.SubstrMatch
}
if _, err = db.ExecContextSQL(ctx, tx,
`INSERT INTO DBPREFIXfilter_conditions(filter_id, match_mode, search, field) VALUES(?,?,?,'body')`,
filterID, matchMode, search,
); err != nil {
return err
}
}
return rows.Close()
}

View file

@ -11,8 +11,7 @@ const (
)
var (
ErrInvalidSchema = errors.New("invalid database schema for old database")
ErrUnsupportedDBType = errors.New("unsupported SQL driver, currently only MySQL and Postgres are supported")
ErrInvalidSchema = errors.New("invalid database schema for old database")
)
type MigrationError struct {
@ -57,8 +56,9 @@ type DBMigrator interface {
// will exit
IsMigrated() (bool, error)
// MigrateDB migrates the imageboard data (posts, boards, etc) to the new database. It is
// assumed that MigrateDB will handle logging any errors that occur during the migration
// MigrateDB alters the database schema to match the new schema, then migrates the imageboard
// data (posts, boards, etc) to the new database. It is assumed that MigrateDB will handle
// logging any errors that occur during the migration
MigrateDB() (bool, error)
// MigrateBoards gets info about the old boards in the board table and inserts each one
@ -83,6 +83,6 @@ type DBMigrator interface {
// and inserts them into the new database,
MigrateAnnouncements() error
// Close closes the database if initialized
// Close closes the database if initialized and deltes the temporary columns created
Close() error
}

View file

@ -16,7 +16,7 @@ import (
)
var (
commentRemover = regexp.MustCompile("--.*\n?")
CommentRemover = regexp.MustCompile("--.*\n?")
)
// ColumnType returns a string representation of the column's data type. It does not return an error
@ -82,7 +82,7 @@ func RunSQLFile(path string, db *gcsql.GCDB) error {
return err
}
sqlStr := commentRemover.ReplaceAllString(string(sqlBytes), " ")
sqlStr := CommentRemover.ReplaceAllString(string(sqlBytes), " ")
sqlArr := strings.Split(sqlStr, ";")
for _, statement := range sqlArr {
@ -96,7 +96,8 @@ func RunSQLFile(path string, db *gcsql.GCDB) error {
return nil
}
func getInitFilePath(initFile string) (string, error) {
// GetInitFilePath returns the path to the given SQL initialization file and returns an error if it is not found
func GetInitFilePath(initFile string) (string, error) {
filePath := gcutil.FindResource(initFile,
path.Join("./sql", initFile),
path.Join("/usr/local/share/gochan", initFile),
@ -108,7 +109,7 @@ func getInitFilePath(initFile string) (string, error) {
}
func InitDB(initFile string, db *gcsql.GCDB) error {
filePath, err := getInitFilePath(initFile)
filePath, err := GetInitFilePath(initFile)
if err != nil {
return err
}

View file

@ -0,0 +1,93 @@
package gcupdate
import (
"context"
"database/sql"
"os"
"strings"
"time"
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/rs/zerolog"
)
// WordFilter represents data in the deprecated wordfilters table
type Wordfilter struct {
ID int // sql: `id`
BoardDirs *string // sql: `board_dirs`
BoardID *int // sql: `board_id`, replaced with board_dirs
StaffID int // sql: `staff_id`
StaffNote string // sql: `staff_note`
IssuedAt time.Time // sql: `issued_at`
Search string // sql: `search`
IsRegex bool // sql: `is_regex`
ChangeTo string // sql: `change_to`
}
type filenameOrUsernameBanBase struct {
ID int // sql: id
BoardID *int // sql: board_id
StaffID int // sql: staff_id
StaffNote string // sql: staff_note
IssuedAt time.Time // sql: issued_at
check string // replaced with username or filename
IsRegex bool // sql: is_regex
}
// UsernameBan represents data in the deprecated username_ban table
type UsernameBan struct {
filenameOrUsernameBanBase
Username string // sql: `username`
}
// FilenameBan represents data in the deprecated filename_ban table
type FilenameBan struct {
filenameOrUsernameBanBase
Filename string // sql: `filename`
IsRegex bool // sql: `is_regex`
}
// FileBan represents data in the deprecated file_ban table
type FileBan struct {
ID int // sql: `id`
BoardID *int // sql: `board_id`
StaffID int // sql: `staff_id`
StaffNote string // sql: `staff_note`
IssuedAt time.Time // sql: `issued_at`
Checksum string // sql: `checksum`
Fingerprinter *string // sql: `fingerprinter`
BanIP bool // sql: `ban_ip`
BanIPMessage *string // sql: `ban_ip_message`
}
// addFilterTables is used for the db version 4 upgrade to create the filter tables from the respective SQL init file
func addFilterTables(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *config.SQLConfig, errEv *zerolog.Event) error {
filePath, err := common.GetInitFilePath("initdb_" + sqlConfig.DBtype + ".sql")
defer func() {
if err != nil {
errEv.Err(err).Caller(1).Send()
}
}()
if err != nil {
return err
}
ba, err := os.ReadFile(filePath)
if err != nil {
return err
}
sqlStr := common.CommentRemover.ReplaceAllString(string(ba), " ")
sqlArr := strings.Split(sqlStr, ";")
for _, stmtStr := range sqlArr {
stmtStr = strings.TrimSpace(stmtStr)
if !strings.HasPrefix(stmtStr, "CREATE TABLE DBPREFIXfilter") {
continue
}
if _, err = db.ExecContextSQL(ctx, tx, stmtStr); err != nil {
return err
}
}
return nil
}

View file

@ -3,13 +3,16 @@ package gcupdate
import (
"context"
"database/sql"
"errors"
"fmt"
"strings"
"time"
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/rs/zerolog"
)
type GCDatabaseUpdater struct {
@ -46,77 +49,321 @@ func (dbu *GCDatabaseUpdater) IsMigrated() (bool, error) {
}
func (dbu *GCDatabaseUpdater) MigrateDB() (bool, error) {
errEv := common.LogError()
gcsql.SetDB(dbu.db)
migrated, err := dbu.IsMigrated()
if migrated || err != nil {
defer func() {
if err != nil {
errEv.Err(err).Caller(1).Send()
}
}()
if err != nil {
return migrated, err
}
if migrated {
return migrated, nil
}
sqlConfig := config.GetSQLConfig()
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
tx, err := dbu.db.BeginTx(ctx, &sql.TxOptions{
Isolation: 0,
ReadOnly: false,
})
var filterTableExists bool
filterTableExists, err = common.TableExists(ctx, dbu.db, nil, "DBPREFIXfilters", &sqlConfig)
if err != nil {
return false, err
}
defer tx.Rollback()
if !filterTableExists {
// DBPREFIXfilters not found, create it and migrate data from DBPREFIXfile_ban, DBPREFIXfilename_ban, and DBPREFIXusername_ban,
if err = addFilterTables(ctx, dbu.db, nil, &sqlConfig, errEv); err != nil {
return false, err
}
}
switch sqlConfig.DBtype {
case "mysql":
err = updateMysqlDB(ctx, dbu.db, tx, &sqlConfig)
err = updateMysqlDB(ctx, dbu, &sqlConfig, errEv)
case "postgres":
err = updatePostgresDB(ctx, dbu.db, tx, &sqlConfig)
err = updatePostgresDB(ctx, dbu, &sqlConfig, errEv)
case "sqlite3":
err = updateSqliteDB(ctx, dbu.db, tx, &sqlConfig)
err = updateSqliteDB(ctx, dbu, &sqlConfig, errEv)
}
if err != nil {
return false, err
}
// commit the transaction and start a new one (to avoid deadlocks)
if err = tx.Commit(); err != nil {
return false, err
}
if err = ctx.Err(); err != nil {
return false, err
}
filterTableExists, err := common.TableExists(ctx, dbu.db, nil, "DBPREFIXfilters", &sqlConfig)
if err != nil {
if err = dbu.migrateFilters(ctx, &sqlConfig, errEv); err != nil {
return false, err
}
if !filterTableExists {
// DBPREFIXfilters not found, create it and migrate data from DBPREFIXfile_bans, DBPREFIXfilename_bans, and DBPREFIXusername_bans,
if err = common.AddFilterTables(ctx, dbu.db, nil, &sqlConfig); err != nil {
return false, err
}
if err = common.MigrateFileBans(ctx, dbu.db, nil, &sqlConfig); err != nil {
return false, err
}
if err = common.MigrateFilenameBans(ctx, dbu.db, nil, &sqlConfig); err != nil {
return false, err
}
if err = common.MigrateUsernameBans(ctx, dbu.db, nil, &sqlConfig); err != nil {
return false, err
}
if err = common.MigrateWordfilters(ctx, dbu.db, nil, &sqlConfig); err != nil {
return false, err
}
}
query := `UPDATE DBPREFIXdatabase_version SET version = ? WHERE component = 'gochan'`
_, err = dbu.db.ExecContextSQL(ctx, nil, query, dbu.TargetDBVer)
if err != nil {
return false, err
}
// return false, tx.Commit()
return false, nil
}
func (dbu *GCDatabaseUpdater) migrateFilters(ctx context.Context, sqlConfig *config.SQLConfig, errEv *zerolog.Event) (err error) {
var fileBansExist, filenameBansExist, usernameBansExist, wordfiltersExist bool
fileBansExist, err = common.TableExists(ctx, dbu.db, nil, "DBPREFIXfile_ban", sqlConfig)
defer func() {
if a := recover(); a != nil {
err = errors.New(fmt.Sprintf("recovered: %v", a))
errEv.Caller(4).Err(err).Send()
errEv.Discard()
} else if err != nil {
errEv.Err(err).Caller(1).Send()
errEv.Discard()
}
}()
if err != nil {
return err
}
filenameBansExist, err = common.TableExists(ctx, dbu.db, nil, "DBPREFIXfilename_ban", sqlConfig)
if err != nil {
return err
}
usernameBansExist, err = common.TableExists(ctx, dbu.db, nil, "DBPREFIXusername_ban", sqlConfig)
if err != nil {
return err
}
wordfiltersExist, err = common.TableExists(ctx, dbu.db, nil, "DBPREFIXwordfilters", sqlConfig)
if err != nil {
return err
}
var rows *sql.Rows
if fileBansExist {
query := "SELECT board_id, staff_id, staff_note, issued_at, checksum, fingerprinter, ban_ip, ban_ip_message FROM DBPREFIXfile_ban"
var fingerprinterCol string
fingerprinterCol, err = common.ColumnType(ctx, dbu.db, nil, "fingerprinter", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if fingerprinterCol == "" {
query = strings.ReplaceAll(query, "fingerprinter", "'checksum' AS fingerprinter")
}
var banIPCol string
banIPCol, err = common.ColumnType(ctx, dbu.db, nil, "ban_ip", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if banIPCol == "" {
query = strings.ReplaceAll(query, "ban_ip", "FALSE AS ban_ip")
}
rows, err = dbu.db.QueryContextSQL(ctx, nil, query)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var ban FileBan
if err = rows.Scan(
&ban.BoardID, &ban.StaffID, &ban.StaffNote, &ban.IssuedAt, &ban.Checksum,
&ban.Fingerprinter, &ban.BanIP, &ban.BanIPMessage,
); err != nil {
return err
}
filter := &gcsql.Filter{
StaffID: &ban.StaffID,
StaffNote: ban.StaffNote,
IssuedAt: ban.IssuedAt,
MatchAction: "reject",
IsActive: true,
}
if ban.BanIP {
filter.MatchAction = "ban"
if ban.BanIPMessage != nil {
filter.MatchDetail = *ban.BanIPMessage
}
}
var boards []int
if ban.BoardID != nil {
boards = append(boards, *ban.BoardID)
}
condition := gcsql.FilterCondition{MatchMode: gcsql.ExactMatch, Search: ban.Checksum, Field: "checksum"}
if ban.Fingerprinter != nil {
condition.Field = *ban.Fingerprinter
}
if err = gcsql.ApplyFilter(filter, []gcsql.FilterCondition{condition}, boards); err != nil {
return err
}
}
if err = rows.Close(); err != nil {
return err
}
}
if filenameBansExist {
query := "SELECT board_id, staff_id, staff_note, issued_at, filename, is_regex FROM DBPREFIXfilename_ban"
rows, err = dbu.db.QueryContextSQL(ctx, nil, query)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var ban FilenameBan
if err = rows.Scan(
&ban.BoardID, &ban.StaffID, &ban.StaffNote, &ban.IssuedAt, &ban.Filename, &ban.IsRegex,
); err != nil {
return err
}
filter := &gcsql.Filter{
StaffID: &ban.StaffID,
StaffNote: ban.StaffNote,
IssuedAt: ban.IssuedAt,
MatchAction: "reject",
IsActive: true,
MatchDetail: "File rejected",
}
condition := gcsql.FilterCondition{MatchMode: gcsql.ExactMatch, Search: ban.Filename, Field: "filename"}
if ban.IsRegex {
condition.MatchMode = gcsql.RegexMatch
}
var boards []int
if ban.BoardID != nil {
boards = append(boards, *ban.BoardID)
}
if err = gcsql.ApplyFilter(filter, []gcsql.FilterCondition{condition}, boards); err != nil {
return err
}
}
if err = rows.Close(); err != nil {
return err
}
}
if usernameBansExist {
query := "SELECT board_id, staff_id, staff_note, issued_at, username FROM DBPREFIXusername_ban"
rows, err = dbu.db.QueryContextSQL(ctx, nil, query)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var ban UsernameBan
if err = rows.Scan(
&ban.BoardID, &ban.StaffID, &ban.StaffNote, &ban.IssuedAt, &ban.Username,
); err != nil {
return err
}
filter := &gcsql.Filter{
StaffID: &ban.StaffID,
StaffNote: ban.StaffNote,
IssuedAt: ban.IssuedAt,
MatchAction: "reject",
IsActive: true,
MatchDetail: "Username rejected",
}
condition := gcsql.FilterCondition{MatchMode: gcsql.ExactMatch, Search: ban.Username, Field: "username"}
if ban.IsRegex {
condition.MatchMode = gcsql.RegexMatch
}
var boards []int
if ban.BoardID != nil {
boards = append(boards, *ban.BoardID)
}
if err = gcsql.ApplyFilter(filter, []gcsql.FilterCondition{condition}, boards); err != nil {
return err
}
}
if err = rows.Close(); err != nil {
return err
}
}
if wordfiltersExist {
query := "SELECT board_dirs, staff_id, staff_note, issued_at, search, is_regex, change_to FROM DBPREFIXwordfilters"
var boardIDCol string
boardIDCol, err = common.ColumnType(ctx, dbu.db, nil, "board_id", "DBPREFIXwordfilters", sqlConfig)
if err != nil {
return err
}
if boardIDCol != "" {
query = strings.ReplaceAll(query, "board_dirs", "board_id")
}
rows, err = dbu.db.QueryContextSQL(ctx, nil, query)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var wf Wordfilter
var boards []int
if boardIDCol != "" {
if err = rows.Scan(
&wf.BoardID, &wf.StaffID, &wf.StaffNote, &wf.IssuedAt, &wf.Search, &wf.IsRegex, &wf.ChangeTo,
); err != nil {
return err
}
if wf.BoardID != nil {
boards = append(boards, *wf.BoardID)
}
} else {
if err = rows.Scan(
&wf.BoardDirs, &wf.StaffID, &wf.StaffNote, &wf.IssuedAt, &wf.Search, &wf.IsRegex, &wf.ChangeTo,
); err != nil {
return err
}
if wf.BoardDirs != nil {
boardDirs := strings.Split(*wf.BoardDirs, ",")
for _, boardDir := range boardDirs {
boardID, err := gcsql.GetBoardIDFromDir(strings.TrimSpace(boardDir))
if err != nil {
return err
}
boards = append(boards, boardID)
}
}
}
filter := &gcsql.Filter{
StaffID: &wf.StaffID,
StaffNote: wf.StaffNote,
IssuedAt: wf.IssuedAt,
MatchAction: "replace",
IsActive: true,
MatchDetail: wf.ChangeTo,
}
condition := gcsql.FilterCondition{MatchMode: gcsql.ExactMatch, Search: wf.Search, Field: "body"}
if wf.IsRegex {
condition.MatchMode = gcsql.RegexMatch
}
if err = gcsql.ApplyFilter(filter, []gcsql.FilterCondition{condition}, boards); err != nil {
return err
}
}
if err = rows.Close(); err != nil {
return err
}
}
return nil
}
func (*GCDatabaseUpdater) MigrateBoards() error {
return gcutil.ErrNotImplemented
}

View file

@ -6,56 +6,31 @@ import (
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/rs/zerolog"
)
func updateMysqlDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *config.SQLConfig) error {
func updateMysqlDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *config.SQLConfig, errEv *zerolog.Event) error {
var query string
var dataType string
dbName := sqlConfig.DBname
wordfiltersTableExists, err := common.TableExists(ctx, db, tx, "DBPREFIXwordfilters", sqlConfig)
if err != nil {
return err
}
if wordfiltersTableExists {
// wordfilters table is going to be migrated by the end of the update, but we want to make sure its legacy data is migrated first
// so it can be properly merged into the filter table
var numConstraints int
query = `SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS
WHERE CONSTRAINT_NAME = 'wordfilters_board_id_fk'
AND TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'DBPREFIXwordfilters'`
if err = db.QueryRowContextSQL(ctx, tx, query, nil, []any{&numConstraints}); err != nil {
return err
}
if numConstraints > 0 {
query = `ALTER TABLE DBPREFIXwordfilters DROP FOREIGN KEY wordfilters_board_id_fk`
} else {
query = ""
}
dataType, err = common.ColumnType(ctx, db, tx, "board_dirs", "DBPREFIXwordfilters", sqlConfig)
var err error
defer func() {
if err != nil {
return err
errEv.Err(err).Caller(1).Send()
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXwordfilters ADD COLUMN board_dirs varchar(255) DEFAULT '*'`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
return err
}
}
}
}()
dbName := sqlConfig.DBname
db := dbu.db
// Yay, collation! Everybody loves MySQL's default collation!
// fix default collation
query = `ALTER DATABASE ` + dbName + ` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.GetBaseDB().ExecContext(ctx, query); err != nil {
return err
}
var rows *sql.Rows
query = `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?`
rows, err := db.QueryContextSQL(ctx, tx, query, dbName)
rows, err = db.QueryContextSQL(ctx, nil, query, dbName)
if err != nil {
return err
}
@ -69,15 +44,15 @@ func updateMysqlDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *c
return err
}
query = `ALTER TABLE ` + tableName + ` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
if err = rows.Close(); err != nil {
return err
}
dataType, err = common.ColumnType(ctx, db, tx, "ip", "DBPREFIXip_ban", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXip_ban", sqlConfig)
if err != nil {
return err
}
@ -86,11 +61,12 @@ func updateMysqlDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *c
query = `ALTER TABLE DBPREFIXip_ban
ADD COLUMN IF NOT EXISTS range_start VARBINARY(16) NOT NULL,
ADD COLUMN IF NOT EXISTS range_end VARBINARY(16) NOT NULL`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
// convert ban IP string to IP range
if rows, err = db.QueryContextSQL(ctx, tx, `SELECT id, ip FROM DBPREFIXip_ban`); err != nil {
if rows, err = db.QueryContextSQL(ctx, nil, "SELECT id, ip FROM DBPREFIXip_ban"); err != nil {
return err
}
var rangeStart, rangeEnd string
@ -105,11 +81,11 @@ func updateMysqlDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *c
}
query = `UPDATE DBPREFIXip_ban
SET range_start = INET6_ATON(?), range_end = INET6_ATON(?) WHERE id = ?`
if _, err = db.ExecContextSQL(ctx, tx, query, rangeStart, rangeEnd, id); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query, rangeStart, rangeEnd, id); err != nil {
return err
}
query = `ALTER TABLE DBPREFIXip_ban DROP COLUMN IF EXISTS ip`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
@ -119,132 +95,88 @@ func updateMysqlDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *c
}
// Convert DBPREFIXposts.ip to from varchar to varbinary
dataType, err = common.ColumnType(ctx, db, tx, "ip", "DBPREFIXposts", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXposts", sqlConfig)
if err != nil {
return err
}
if common.IsStringType(dataType) {
// rename `ip` to a temporary column to then be removed
query = `ALTER TABLE DBPREFIXposts CHANGE ip ip_str varchar(45)`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
query = "ALTER TABLE DBPREFIXposts CHANGE ip ip_str varchar(45)"
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
query = `ALTER TABLE DBPREFIXposts
ADD COLUMN IF NOT EXISTS ip VARBINARY(16) NOT NULL`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
// convert post IP VARCHAR(45) to VARBINARY(16)
query = `UPDATE DBPREFIXposts SET ip = INET6_ATON(ip_str)`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
query = `ALTER TABLE DBPREFIXposts DROP COLUMN IF EXISTS ip_str`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// Convert DBPREFIXreports.ip to from varchar to varbinary
dataType, err = common.ColumnType(ctx, db, tx, "ip", "DBPREFIXreports", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXreports", sqlConfig)
if err != nil {
return err
}
if common.IsStringType(dataType) {
// rename `ip` to a temporary column to then be removed
query = `ALTER TABLE DBPREFIXreports CHANGE ip ip_str varchar(45)`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
query = "ALTER TABLE DBPREFIXreports CHANGE ip ip_str varchar(45)"
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
query = `ALTER TABLE DBPREFIXreports
ADD COLUMN IF NOT EXISTS ip VARBINARY(16) NOT NULL`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
// convert report IP VARCHAR(45) to VARBINARY(16)
query = `UPDATE DBPREFIXreports SET ip = INET6_ATON(ip_str)`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
query = `ALTER TABLE DBPREFIXreports DROP COLUMN IF EXISTS ip_str`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// add flag column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, tx, "flag", "DBPREFIXposts", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "flag", "DBPREFIXposts", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN flag VARCHAR(45) NOT NULL DEFAULT ''`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// add country column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, tx, "country", "DBPREFIXposts", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "country", "DBPREFIXposts", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN country VARCHAR(80) NOT NULL DEFAULT ''`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
fileBanTableExists, err := common.TableExists(ctx, db, tx, "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if fileBanTableExists {
// file ban table is going to be migrated by the end of the update, but we want to make sure its legacy data is migrated first
// so it can be properly merged into the filter table
// add fingerprinter column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "fingerprinter", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN fingerprinter VARCHAR(64)`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
return err
}
}
// add ban_ip column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "ban_ip", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN ban_ip BOOL NOT NULL`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
return err
}
}
// add ban_ip_message column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "ban_ip_message", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN ban_ip_message TEXT`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
return err
}
}
}
return nil
}

View file

@ -2,35 +2,29 @@ package gcupdate
import (
"context"
"database/sql"
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/rs/zerolog"
)
func updatePostgresDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *config.SQLConfig) error {
func updatePostgresDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *config.SQLConfig, errEv *zerolog.Event) error {
db := dbu.db
var query string
query := `ALTER TABLE DBPREFIXwordfilters
DROP CONSTRAINT IF EXISTS board_id_fk`
_, err := db.ExecContextSQL(ctx, tx, query)
if err != nil {
return err
}
query = `ALTER TABLE DBPREFIXwordfilters
ADD COLUMN IF NOT EXISTS board_dirs varchar(255) DEFAULT '*'`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
return err
}
dataType, err := common.ColumnType(ctx, db, tx, "ip", "DBPREFIXposts", sqlConfig)
dataType, err := common.ColumnType(ctx, db, nil, "ip", "DBPREFIXposts", sqlConfig)
defer func() {
if err != nil {
errEv.Err(err).Caller(1).Send()
}
}()
if err != nil {
return err
}
if common.IsStringType(dataType) {
// change ip column to temporary ip_str
query = `ALTER TABLE DBPREFIXposts RENAME COLUMN ip TO ip_str,`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
@ -38,22 +32,22 @@ func updatePostgresDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig
// because it is non-nil
query = `ALTER TABLE DBPREFIXposts
ADD COLUMN IF NOT EXISTS ip INET NOT NULL DEFAULT '127.0.0.1'`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
query = `UPDATE TABLE DBPREFIXposts SET ip = ip_str`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
query = `ALTER TABLE DBPREFIXposts DROP COLUMN ip_str`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
dataType, err = common.ColumnType(ctx, db, tx, "ip", "DBPREFIXip_ban", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXip_ban", sqlConfig)
if err != nil {
return err
}
@ -61,72 +55,36 @@ func updatePostgresDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig
query = `ALTER TABLE DBPREFIXip_ban
ADD COLUMN IF NOT EXISTS range_start INET NOT NULL,
ADD COLUMN IF NOT EXISTS range_end INET NOT NULL`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
query = `UPDATE DBPREFIXip_ban SET range_start = ip::INET, SET range_end = ip::INET`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// add flag column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, tx, "flag", "DBPREFIXposts", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "flag", "DBPREFIXposts", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN flag VARCHAR(45) NOT NULL DEFAULT ''`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// add country column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, tx, "country", "DBPREFIXposts", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "country", "DBPREFIXposts", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN country VARCHAR(80) NOT NULL DEFAULT ''`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
return err
}
}
// add fingerprinter column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "fingerprinter", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN fingerprinter VARCHAR(64)`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
return err
}
}
// add ban_ip column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "ban_ip", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN ban_ip BOOL NOT NULL`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
return err
}
}
// add ban_ip_message column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "ban_ip_message", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN ban_ip_message TEXT`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}

View file

@ -2,112 +2,107 @@ package gcupdate
import (
"context"
"database/sql"
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/rs/zerolog"
)
func updateSqliteDB(ctx context.Context, db *gcsql.GCDB, tx *sql.Tx, sqlConfig *config.SQLConfig) error {
func updateSqliteDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *config.SQLConfig, errEv *zerolog.Event) error {
db := dbu.db
var query string
_, err := db.ExecContextSQL(ctx, tx, `PRAGMA foreign_keys = ON`)
if err != nil {
return err
}
dataType, err := common.ColumnType(ctx, db, tx, "DBPREFIXwordfilters", "board_dirs", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXwordfilters ADD COLUMN board_dirs varchar(255) DEFAULT '*'`
if _, err = db.ExecTxSQL(tx, query); err != nil {
return err
_, err := db.ExecContextSQL(ctx, nil, `PRAGMA foreign_keys = ON`)
defer func() {
if err != nil {
errEv.Err(err).Caller(1).Send()
}
}()
if err != nil {
return err
}
var dataType string
// Add range_start column to DBPREFIXIp_ban if it doesn't exist
dataType, err = common.ColumnType(ctx, db, tx, "DBPREFIXip_ban", "range_start", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "DBPREFIXip_ban", "range_start", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXip_ban ADD COLUMN range_start VARCHAR(45) NOT NULL`
if _, err = db.ExecTxSQL(tx, query); err != nil {
if _, err = db.ExecTxSQL(nil, query); err != nil {
return err
}
}
// Add range_start column if it doesn't exist
dataType, err = common.ColumnType(ctx, db, tx, "DBPREFIXip_ban", "range_end", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "DBPREFIXip_ban", "range_end", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXip_ban ADD COLUMN range_end VARCHAR(45) NOT NULL`
if _, err = db.ExecTxSQL(tx, query); err != nil {
if _, err = db.ExecTxSQL(nil, query); err != nil {
return err
}
}
// add flag column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, tx, "flag", "DBPREFIXposts", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "flag", "DBPREFIXposts", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN flag VARCHAR(45) NOT NULL DEFAULT ''`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// add country column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, tx, "country", "DBPREFIXposts", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "country", "DBPREFIXposts", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN country VARCHAR(80) NOT NULL DEFAULT ''`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// add fingerprinter column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "fingerprinter", "DBPREFIXfile_ban", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "fingerprinter", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN fingerprinter VARCHAR(64)`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// add ban_ip column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "ban_ip", "DBPREFIXfile_ban", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "ban_ip", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN ban_ip BOOL NOT NULL`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}
// add ban_ip_message column to DBPREFIXfile_ban
dataType, err = common.ColumnType(ctx, db, tx, "ban_ip_message", "DBPREFIXfile_ban", sqlConfig)
dataType, err = common.ColumnType(ctx, db, nil, "ban_ip_message", "DBPREFIXfile_ban", sqlConfig)
if err != nil {
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXfile_ban ADD COLUMN ban_ip_message TEXT`
if _, err = db.ExecContextSQL(ctx, tx, query); err != nil {
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
return err
}
}