2020-01-03 15:07:05 +01:00
// Copyright 2017-2018 New Vector Ltd
// Copyright 2019-2020 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
2020-05-28 12:15:21 +02:00
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implie
2020-01-03 15:07:05 +01:00
// See the License for the specific language governing permissions and
// limitations under the License.
package postgres
import (
2022-09-09 14:14:52 +02:00
"context"
2020-01-03 15:07:05 +01:00
"database/sql"
2022-09-09 14:14:52 +02:00
"errors"
2021-04-26 14:25:57 +02:00
"fmt"
2020-03-17 16:12:01 +01:00
2020-11-05 11:19:23 +01:00
// Import the postgres database driver.
_ "github.com/lib/pq"
2022-08-08 10:18:57 +02:00
2020-08-25 13:32:29 +02:00
"github.com/matrix-org/dendrite/internal/caching"
2020-04-16 11:06:55 +02:00
"github.com/matrix-org/dendrite/internal/sqlutil"
2020-11-05 11:19:23 +01:00
"github.com/matrix-org/dendrite/roomserver/storage/postgres/deltas"
2020-05-26 16:42:42 +02:00
"github.com/matrix-org/dendrite/roomserver/storage/shared"
2020-12-02 18:41:00 +01:00
"github.com/matrix-org/dendrite/setup/config"
2020-01-03 15:07:05 +01:00
)
// A Database is used to store room events and stream offsets.
type Database struct {
2020-05-26 16:42:42 +02:00
shared . Database
2020-01-03 15:07:05 +01:00
}
// Open a postgres database.
2023-03-17 12:09:45 +01:00
func Open ( ctx context . Context , conMan sqlutil . Connections , dbProperties * config . DatabaseOptions , cache caching . RoomServerCaches ) ( * Database , error ) {
2020-01-03 15:07:05 +01:00
var d Database
var err error
2023-03-17 12:09:45 +01:00
db , writer , err := conMan . Connection ( dbProperties )
2022-05-03 17:35:06 +02:00
if err != nil {
2021-04-26 14:25:57 +02:00
return nil , fmt . Errorf ( "sqlutil.Open: %w" , err )
2020-01-03 15:07:05 +01:00
}
2020-11-05 11:19:23 +01:00
2021-04-26 14:25:57 +02:00
// Create the tables.
2022-07-25 11:39:22 +02:00
if err = d . create ( db ) ; err != nil {
2020-11-05 11:19:23 +01:00
return nil , err
}
2021-04-26 14:25:57 +02:00
2022-07-25 11:39:22 +02:00
// Special case, since this migration uses several tables, so it needs to
// be sure that all tables are created first.
2023-03-17 12:09:45 +01:00
if err = executeMigration ( ctx , db ) ; err != nil {
2022-09-09 14:14:52 +02:00
return nil , err
2020-11-05 11:19:23 +01:00
}
2021-04-26 14:25:57 +02:00
// Then prepare the statements. Now that the migrations have run, any columns referred
// to in the database code should now exist.
2022-08-08 10:18:57 +02:00
if err = d . prepare ( db , writer , cache ) ; err != nil {
2020-11-05 11:19:23 +01:00
return nil , err
}
return & d , nil
}
2022-09-09 14:14:52 +02:00
func executeMigration ( ctx context . Context , db * sql . DB ) error {
// TODO: Remove when we are sure we are not having goose artefacts in the db
// This forces an error, which indicates the migration is already applied, since the
// column event_nid was removed from the table
migrationName := "roomserver: state blocks refactor"
var cName string
err := db . QueryRowContext ( ctx , "select column_name from information_schema.columns where table_name = 'roomserver_state_block' AND column_name = 'event_nid'" ) . Scan ( & cName )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) { // migration was already executed, as the column was removed
if err = sqlutil . InsertMigration ( ctx , db , migrationName ) ; err != nil {
2022-09-13 08:07:43 +02:00
return fmt . Errorf ( "unable to manually insert migration '%s': %w" , migrationName , err )
2022-09-09 14:14:52 +02:00
}
return nil
}
return err
}
m := sqlutil . NewMigrator ( db )
m . AddMigrations ( sqlutil . Migration {
Version : migrationName ,
Up : deltas . UpStateBlocksRefactor ,
} )
return m . Up ( ctx )
}
2021-04-26 14:25:57 +02:00
func ( d * Database ) create ( db * sql . DB ) error {
2022-05-09 15:30:32 +02:00
if err := CreateEventStateKeysTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-09 15:30:32 +02:00
if err := CreateEventTypesTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-09 15:30:32 +02:00
if err := CreateEventJSONTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-09 15:30:32 +02:00
if err := CreateEventsTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-16 19:33:16 +02:00
if err := CreateRoomsTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-16 19:33:16 +02:00
if err := CreateStateBlockTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-16 19:33:16 +02:00
if err := CreateStateSnapshotTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-10 14:41:12 +02:00
if err := CreatePrevEventsTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-16 19:33:16 +02:00
if err := CreateRoomAliasesTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-10 14:41:12 +02:00
if err := CreateInvitesTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-10 14:41:12 +02:00
if err := CreateMembershipTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-10 14:41:12 +02:00
if err := CreatePublishedTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
2022-05-10 14:41:12 +02:00
if err := CreateRedactionsTable ( db ) ; err != nil {
2021-04-26 14:25:57 +02:00
return err
}
return nil
}
2022-05-03 17:35:06 +02:00
func ( d * Database ) prepare ( db * sql . DB , writer sqlutil . Writer , cache caching . RoomServerCaches ) error {
2022-05-09 15:30:32 +02:00
eventStateKeys , err := PrepareEventStateKeysTable ( db )
2020-05-26 16:42:42 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-26 16:42:42 +02:00
}
2022-05-09 15:30:32 +02:00
eventTypes , err := PrepareEventTypesTable ( db )
2020-05-26 16:42:42 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-26 16:42:42 +02:00
}
2022-05-09 15:30:32 +02:00
eventJSON , err := PrepareEventJSONTable ( db )
2020-05-26 17:45:28 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-26 17:45:28 +02:00
}
2022-05-09 15:30:32 +02:00
events , err := PrepareEventsTable ( db )
2020-05-26 17:45:28 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-26 17:45:28 +02:00
}
2022-05-16 19:33:16 +02:00
rooms , err := PrepareRoomsTable ( db )
2020-05-26 19:23:39 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-26 19:23:39 +02:00
}
2022-05-16 19:33:16 +02:00
stateBlock , err := PrepareStateBlockTable ( db )
2020-05-27 10:36:09 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-27 10:36:09 +02:00
}
2022-05-16 19:33:16 +02:00
stateSnapshot , err := PrepareStateSnapshotTable ( db )
2020-05-27 10:36:09 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-27 10:36:09 +02:00
}
2022-05-10 14:41:12 +02:00
prevEvents , err := PreparePrevEventsTable ( db )
2020-05-27 10:36:09 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-27 10:36:09 +02:00
}
2022-05-16 19:33:16 +02:00
roomAliases , err := PrepareRoomAliasesTable ( db )
2020-05-27 10:36:09 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-27 10:36:09 +02:00
}
2022-05-10 14:41:12 +02:00
invites , err := PrepareInvitesTable ( db )
2020-05-27 12:03:47 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-27 12:03:47 +02:00
}
2022-05-10 14:41:12 +02:00
membership , err := PrepareMembershipTable ( db )
2020-05-27 12:03:47 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-05-27 12:03:47 +02:00
}
2022-05-10 14:41:12 +02:00
published , err := PreparePublishedTable ( db )
2020-07-02 16:41:18 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-07-02 16:41:18 +02:00
}
2022-05-10 14:41:12 +02:00
redactions , err := PrepareRedactionsTable ( db )
2020-07-06 18:49:15 +02:00
if err != nil {
2020-11-05 11:19:23 +01:00
return err
2020-07-06 18:49:15 +02:00
}
2023-01-19 21:02:32 +01:00
purge , err := PreparePurgeStatements ( db )
if err != nil {
return err
}
2020-05-26 16:42:42 +02:00
d . Database = shared . Database {
2023-03-01 17:06:47 +01:00
DB : db ,
EventDatabase : shared . EventDatabase {
DB : db ,
Cache : cache ,
Writer : writer ,
EventsTable : events ,
EventJSONTable : eventJSON ,
EventTypesTable : eventTypes ,
EventStateKeysTable : eventStateKeys ,
PrevEventsTable : prevEvents ,
RedactionsTable : redactions ,
} ,
Cache : cache ,
Writer : writer ,
RoomsTable : rooms ,
StateBlockTable : stateBlock ,
StateSnapshotTable : stateSnapshot ,
RoomAliasesTable : roomAliases ,
InvitesTable : invites ,
MembershipTable : membership ,
PublishedTable : published ,
Purge : purge ,
2020-05-26 16:42:42 +02:00
}
2020-11-05 11:19:23 +01:00
return nil
2020-01-03 15:07:05 +01:00
}