From a439d11f668b3f3204b8742c9013d3e7e2882b67 Mon Sep 17 00:00:00 2001 From: Miguel de la Cruz <miguel@mcrx.me> Date: Mon, 25 Apr 2022 17:43:06 +0200 Subject: [PATCH] Handle jsonb fields on postgres with binary_parameters set (#2854) * Handle jsonb fields on postgres with binary_parameters set * Finx linter adding dot --- server/services/store/sqlstore/board.go | 12 +++++------ server/services/store/sqlstore/sqlstore.go | 25 +++++++++++++++++++++- server/services/store/sqlstore/util.go | 14 ++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/server/services/store/sqlstore/board.go b/server/services/store/sqlstore/board.go index 193bc38d4..80f3e4861 100644 --- a/server/services/store/sqlstore/board.go +++ b/server/services/store/sqlstore/board.go @@ -268,7 +268,7 @@ func (s *SQLStore) getBoardsForUserAndTeam(db sq.BaseRunner, userID, teamID stri } func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID string) (*model.Board, error) { - propertiesBytes, err := json.Marshal(board.Properties) + propertiesBytes, err := s.MarshalJSONB(board.Properties) if err != nil { s.logger.Error( "failed to marshal board.Properties", @@ -279,7 +279,7 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri return nil, err } - cardPropertiesBytes, err := json.Marshal(board.CardProperties) + cardPropertiesBytes, err := s.MarshalJSONB(board.CardProperties) if err != nil { s.logger.Error( "failed to marshal board.CardProperties", @@ -382,11 +382,11 @@ func (s *SQLStore) deleteBoard(db sq.BaseRunner, boardID, userID string) error { return err } - propertiesBytes, err := json.Marshal(board.Properties) + propertiesBytes, err := s.MarshalJSONB(board.Properties) if err != nil { return err } - cardPropertiesBytes, err := json.Marshal(board.CardProperties) + cardPropertiesBytes, err := s.MarshalJSONB(board.CardProperties) if err != nil { return err } @@ -692,12 +692,12 @@ func (s *SQLStore) undeleteBoard(db sq.BaseRunner, boardID string, modifiedBy st return nil // undeleting not deleted board is not considered an error (for now) } - propertiesJSON, err := json.Marshal(board.Properties) + propertiesJSON, err := s.MarshalJSONB(board.Properties) if err != nil { return err } - cardPropertiesJSON, err := json.Marshal(board.CardProperties) + cardPropertiesJSON, err := s.MarshalJSONB(board.CardProperties) if err != nil { return err } diff --git a/server/services/store/sqlstore/sqlstore.go b/server/services/store/sqlstore/sqlstore.go index d4af54c0b..7e164268c 100644 --- a/server/services/store/sqlstore/sqlstore.go +++ b/server/services/store/sqlstore/sqlstore.go @@ -2,6 +2,7 @@ package sqlstore import ( "database/sql" + "net/url" "github.com/mattermost/mattermost-server/v6/plugin" @@ -24,6 +25,7 @@ type SQLStore struct { logger *mlog.Logger NewMutexFn MutexFactory pluginAPI *plugin.API + isBinaryParam bool } // MutexFactory is used by the store in plugin mode to generate @@ -49,7 +51,14 @@ func New(params Params) (*SQLStore, error) { pluginAPI: params.PluginAPI, } - err := store.Migrate() + var err error + store.isBinaryParam, err = store.computeBinaryParam() + if err != nil { + params.Logger.Error(`Cannot compute binary parameter`, mlog.Err(err)) + return nil, err + } + + err = store.Migrate() if err != nil { params.Logger.Error(`Table creation / migration failed`, mlog.Err(err)) @@ -58,6 +67,20 @@ func New(params Params) (*SQLStore, error) { return store, nil } +// computeBinaryParam returns whether the data source uses binary_parameters +// when using Postgres. +func (s *SQLStore) computeBinaryParam() (bool, error) { + if s.dbType != model.PostgresDBType { + return false, nil + } + + url, err := url.Parse(s.connectionString) + if err != nil { + return false, err + } + return url.Query().Get("binary_parameters") == "yes", nil +} + // Shutdown close the connection with the store. func (s *SQLStore) Shutdown() error { return s.db.Close() diff --git a/server/services/store/sqlstore/util.go b/server/services/store/sqlstore/util.go index 184dcf09a..8a01e933d 100644 --- a/server/services/store/sqlstore/util.go +++ b/server/services/store/sqlstore/util.go @@ -2,6 +2,7 @@ package sqlstore import ( "database/sql" + "encoding/json" "fmt" "io/ioutil" "os" @@ -23,6 +24,19 @@ func (s *SQLStore) IsErrNotFound(err error) bool { return model.IsErrNotFound(err) } +func (s *SQLStore) MarshalJSONB(data interface{}) ([]byte, error) { + b, err := json.Marshal(data) + if err != nil { + return nil, err + } + + if s.isBinaryParam { + b = append([]byte{0x01}, b...) + } + + return b, nil +} + func PrepareNewTestDatabase() (dbType string, connectionString string, err error) { dbType = strings.TrimSpace(os.Getenv("FB_STORE_TEST_DB_TYPE")) if dbType == "" {