From b7b6a0fc3f1012c55c70f7cb8a4dcacd99810dc1 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 24 Oct 2023 15:38:03 +0200 Subject: [PATCH 01/23] chore(embedded/sql): wip emulate pg_type system table Signed-off-by: Jeronimo Irazabal --- embedded/sql/catalog.go | 47 +++++++++++++++++++++++++++++++++++++- embedded/sql/row_reader.go | 31 ++++++++++++++++++++++--- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/embedded/sql/catalog.go b/embedded/sql/catalog.go index 5326d5987a..fd6a0877cc 100644 --- a/embedded/sql/catalog.go +++ b/embedded/sql/catalog.go @@ -79,11 +79,56 @@ type Column struct { } func newCatalog(enginePrefix []byte) *Catalog { - return &Catalog{ + ctlg := &Catalog{ enginePrefix: enginePrefix, tablesByID: make(map[uint32]*Table), tablesByName: make(map[string]*Table), } + + pgTypeTable := &Table{ + catalog: ctlg, + name: "pg_type", + cols: []*Column{ + { + colName: "oid", + colType: VarcharType, + maxLen: 10, + }, + { + colName: "typbasetype", + colType: VarcharType, + maxLen: 10, + }, + { + colName: "typname", + colType: VarcharType, + maxLen: 50, + }, + }, + } + + pgTypeTable.colsByName = make(map[string]*Column, len(pgTypeTable.cols)) + + for _, col := range pgTypeTable.cols { + pgTypeTable.colsByName[col.colName] = col + } + + pgTypeTable.indexes = []*Index{ + { + unique: true, + cols: []*Column{ + pgTypeTable.colsByName["oid"], + }, + colsByID: map[uint32]*Column{ + 0: pgTypeTable.colsByName["oid"], + }, + }, + } + + pgTypeTable.primaryIndex = pgTypeTable.indexes[0] + ctlg.tablesByName[pgTypeTable.name] = pgTypeTable + + return ctlg } func (catlg *Catalog) ExistTable(table string) bool { diff --git a/embedded/sql/row_reader.go b/embedded/sql/row_reader.go index 2f8ef7bf84..9fdf75991c 100644 --- a/embedded/sql/row_reader.go +++ b/embedded/sql/row_reader.go @@ -145,6 +145,25 @@ func (d *ColDescriptor) Selector() string { return EncodeSelector(d.AggFn, d.Table, d.Column) } +type emptyKeyReader struct { +} + +func (r emptyKeyReader) Read(ctx context.Context) (key []byte, val store.ValueRef, err error) { + return nil, nil, store.ErrNoMoreEntries +} + +func (r emptyKeyReader) ReadBetween(ctx context.Context, initialTxID uint64, finalTxID uint64) (key []byte, val store.ValueRef, err error) { + return nil, nil, store.ErrNoMoreEntries +} + +func (r emptyKeyReader) Reset() error { + return nil +} + +func (r emptyKeyReader) Close() error { + return nil +} + func newRawRowReader(tx *SQLTx, params map[string]interface{}, table *Table, period period, tableAlias string, scanSpecs *ScanSpecs) (*rawRowReader, error) { if table == nil || scanSpecs == nil || scanSpecs.Index == nil { return nil, ErrIllegalArguments @@ -155,9 +174,15 @@ func newRawRowReader(tx *SQLTx, params map[string]interface{}, table *Table, per return nil, err } - r, err := tx.newKeyReader(*rSpec) - if err != nil { - return nil, err + var r store.KeyReader + + if table.name == "pg_type" { + r = &emptyKeyReader{} + } else { + r, err = tx.newKeyReader(*rSpec) + if err != nil { + return nil, err + } } if tableAlias == "" { From 36ddf897b42e0f559408aeba95a2d188a1ff7952 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 24 Oct 2023 15:38:31 +0200 Subject: [PATCH 02/23] chore(pkg/pgsql): uuid and float types conversion Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/pgmeta/pg_type.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/pgsql/server/pgmeta/pg_type.go b/pkg/pgsql/server/pgmeta/pg_type.go index 9669a6c8b0..357f3dd19c 100644 --- a/pkg/pgsql/server/pgmeta/pg_type.go +++ b/pkg/pgsql/server/pgmeta/pg_type.go @@ -31,11 +31,13 @@ var PgsqlProtocolVersionMessage = fmt.Sprintf("pgsql wire protocol %s or greater // First int is the oid value (retrieved with select * from pg_type;) // Second int is the length of the value. -1 for dynamic. var PgTypeMap = map[string][]int{ - "BOOLEAN": {16, 1}, //bool - "BLOB": {17, -1}, //bytea - "TIMESTAMP": {20, 8}, //int8 - "INTEGER": {20, 8}, //int8 - "VARCHAR": {25, -1}, //text + "BOOLEAN": {16, 1}, //bool + "BLOB": {17, -1}, //bytea + "TIMESTAMP": {20, 8}, //int8 + "INTEGER": {20, 8}, //int8 + "VARCHAR": {25, -1}, //text + "UUID": {2950, 16}, //uuid + "FLOAT": {701, 8}, //double-precision floating point number } const PgSeverityError = "ERROR" From e485f01bfb0278ef7d4226c905f88c87593a70ac Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 24 Oct 2023 15:39:02 +0200 Subject: [PATCH 03/23] chore(pkg/pgsql): handle deallocate prepared stmt Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/stmts_handler.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/pgsql/server/stmts_handler.go b/pkg/pgsql/server/stmts_handler.go index 88a0ddafa8..0f70005df9 100644 --- a/pkg/pgsql/server/stmts_handler.go +++ b/pkg/pgsql/server/stmts_handler.go @@ -24,6 +24,7 @@ import ( var set = regexp.MustCompile(`(?i)set\s+.+`) var selectVersion = regexp.MustCompile(`(?i)select\s+version\(\s*\)`) +var dealloc = regexp.MustCompile(`(?i)deallocate\s+\"([^\"]+)\"`) func (s *session) isInBlackList(statement string) bool { if set.MatchString(statement) { @@ -39,14 +40,24 @@ func (s *session) isEmulableInternally(statement string) interface{} { if selectVersion.MatchString(statement) { return &version{} } + + if dealloc.MatchString(statement) { + matches := dealloc.FindStringSubmatch(statement) + if len(matches) == 2 { + return &deallocate{plan: matches[1]} + } + } return nil } func (s *session) tryToHandleInternally(command interface{}) error { - switch command.(type) { + switch cmd := command.(type) { case *version: if err := s.writeVersionInfo(); err != nil { return err } + case *deallocate: + delete(s.statements, cmd.plan) + return nil default: return pserr.ErrMessageCannotBeHandledInternally } @@ -54,3 +65,7 @@ func (s *session) tryToHandleInternally(command interface{}) error { } type version struct{} + +type deallocate struct { + plan string +} From a48a86c30f7a081a42891e371f594f201f2a08d6 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 24 Oct 2023 15:39:43 +0200 Subject: [PATCH 04/23] chore(pkg/pgsql): decouple error from ready to query messages Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/session.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/pkg/pgsql/server/session.go b/pkg/pgsql/server/session.go index 551bc26ec4..da71d146ca 100644 --- a/pkg/pgsql/server/session.go +++ b/pkg/pgsql/server/session.go @@ -28,7 +28,6 @@ import ( "github.com/codenotary/immudb/pkg/auth" "github.com/codenotary/immudb/pkg/database" "github.com/codenotary/immudb/pkg/pgsql/errors" - bm "github.com/codenotary/immudb/pkg/pgsql/server/bmessages" fm "github.com/codenotary/immudb/pkg/pgsql/server/fmessages" "github.com/codenotary/immudb/pkg/pgsql/server/pgmeta" ) @@ -67,16 +66,10 @@ func NewSession(c net.Conn, log logger.Logger, sysDb database.DB, tlsConfig *tls } func (s *session) ErrorHandle(e error) { - if e != nil { - er := errors.MapPgError(e) - _, err := s.writeMessage(er.Encode()) - if err != nil { - s.log.Errorf("unable to write error on wire: %v", err) - } - s.log.Debugf("%s", er.ToString()) - if _, err := s.writeMessage(bm.ReadyForQuery()); err != nil { - s.log.Errorf("unable to complete error handling: %v", err) - } + pgerr := errors.MapPgError(e) + _, err := s.writeMessage(pgerr.Encode()) + if err != nil { + s.log.Errorf("unable to write error on wire: %w", err) } } From b0e42fb51b1591aac70998ea86bd0c4c6953e933 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 24 Oct 2023 15:40:32 +0200 Subject: [PATCH 05/23] chore(pkg/pgsql): pgsql write protocol improvements Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/query_machine.go | 183 +++++++++++++++++------------- 1 file changed, 103 insertions(+), 80 deletions(-) diff --git a/pkg/pgsql/server/query_machine.go b/pkg/pgsql/server/query_machine.go index dc718bf87a..c9d47b66ba 100644 --- a/pkg/pgsql/server/query_machine.go +++ b/pkg/pgsql/server/query_machine.go @@ -46,13 +46,14 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { for { msg, extQueryMode, err := s.nextMessage() if err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { s.log.Warningf("connection is closed") return nil } s.ErrorHandle(err) continue } + // When an error is detected while processing any extended-query message, the backend issues ErrorResponse, // then reads and discards messages until a Sync is reached, then issues ReadyForQuery and returns to normal // message processing. (But note that no skipping occurs if an error is detected while processing Sync — this @@ -67,34 +68,71 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { case fm.TerminateMsg: return s.mr.CloseConnection() case fm.QueryMsg: - if err = s.fetchAndWriteResults(ctx, v.GetStatements(), nil, nil, false); err != nil { - s.ErrorHandle(err) - continue - } - if _, err = s.writeMessage(bm.CommandComplete([]byte(`ok`))); err != nil { + err := s.fetchAndWriteResults(ctx, v.GetStatements(), nil, nil, false) + if err != nil { + waitForSync = extQueryMode s.ErrorHandle(err) - continue } + if _, err = s.writeMessage(bm.ReadyForQuery()); err != nil { - s.ErrorHandle(err) - continue + waitForSync = extQueryMode } case fm.ParseMsg: + _, ok := s.statements[v.DestPreparedStatementName] + // unnamed prepared statement overrides previous + if ok && v.DestPreparedStatementName != "" { + waitForSync = extQueryMode + s.ErrorHandle(fmt.Errorf("statement '%s' already present", v.DestPreparedStatementName)) + continue + } + var paramCols []*schema.Column var resCols []*schema.Column var stmt sql.SQLStmt - if !s.isInBlackList(v.Statements) { - if paramCols, resCols, err = s.inferParamAndResultCols(ctx, v.Statements); err != nil { - s.ErrorHandle(err) - waitForSync = true - continue + + if s.isInBlackList(v.Statements) { + _, err := s.writeMessage(bm.ParseComplete()) + if err != nil { + waitForSync = extQueryMode } + continue } - _, ok := s.statements[v.DestPreparedStatementName] - // unnamed prepared statement overrides previous - if ok && v.DestPreparedStatementName != "" { - s.ErrorHandle(errors.New("statement already present")) - waitForSync = true + + // todo @Michele The query string contained in a Parse message cannot include more than one SQL statement; + // else a syntax error is reported. This restriction does not exist in the simple-query protocol, + // but it does exist in the extended protocol, because allowing prepared statements or portals to contain + // multiple commands would complicate the protocol unduly. + stmts, err := sql.Parse(strings.NewReader(v.Statements)) + if err != nil { + waitForSync = extQueryMode + s.ErrorHandle(err) + continue + } + + // The query string contained in a Parse message cannot include more than one SQL statement; + // else a syntax error is reported. This restriction does not exist in the simple-query protocol, but it does exist + // in the extended protocol, because allowing prepared statements or portals to contain multiple commands would + // complicate the protocol unduly. + if len(stmts) > 1 { + waitForSync = extQueryMode + s.ErrorHandle(pserr.ErrMaxStmtNumberExceeded) + continue + } + if len(stmts) == 0 { + waitForSync = extQueryMode + s.ErrorHandle(pserr.ErrNoStatementFound) + continue + } + + if paramCols, resCols, err = s.inferParamAndResultCols(ctx, stmts[0]); err != nil { + waitForSync = extQueryMode + s.ErrorHandle(err) + continue + } + + _, err = s.writeMessage(bm.ParseComplete()) + if err != nil { + waitForSync = extQueryMode continue } @@ -109,11 +147,6 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { s.statements[v.DestPreparedStatementName] = newStatement - if _, err = s.writeMessage(bm.ParseComplete()); err != nil { - s.ErrorHandle(err) - waitForSync = true - continue - } case fm.DescribeMsg: // The Describe message (statement variant) specifies the name of an existing prepared statement // (or an empty string for the unnamed prepared statement). The response is a ParameterDescription @@ -126,18 +159,18 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { if v.DescType == "S" { st, ok := s.statements[v.Name] if !ok { - s.ErrorHandle(errors.New("statement not found")) - waitForSync = true + waitForSync = extQueryMode + s.ErrorHandle(fmt.Errorf("statement '%s' not found", v.Name)) continue } + if _, err = s.writeMessage(bm.ParameterDescription(st.Params)); err != nil { - s.ErrorHandle(err) - waitForSync = true + waitForSync = extQueryMode continue } + if _, err := s.writeMessage(bm.RowDescription(st.Results, nil)); err != nil { - s.ErrorHandle(err) - waitForSync = true + waitForSync = extQueryMode continue } } @@ -146,42 +179,46 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { // returned by executing the portal; or a NoData message if the portal does not contain a query that // will return rows; or ErrorResponse if there is no such portal. if v.DescType == "P" { - st, ok := s.portals[v.Name] + portal, ok := s.portals[v.Name] if !ok { - s.ErrorHandle(fmt.Errorf("portal %s not found", v.Name)) - waitForSync = true + waitForSync = extQueryMode + s.ErrorHandle(fmt.Errorf("portal '%s' not found", v.Name)) continue } - if _, err = s.writeMessage(bm.RowDescription(st.Statement.Results, st.ResultColumnFormatCodes)); err != nil { - s.ErrorHandle(err) - waitForSync = true + + if _, err = s.writeMessage(bm.RowDescription(portal.Statement.Results, portal.ResultColumnFormatCodes)); err != nil { + waitForSync = extQueryMode continue } } case fm.SyncMsg: - if _, err = s.writeMessage(bm.ReadyForQuery()); err != nil { - s.ErrorHandle(err) - } + waitForSync = false + s.writeMessage(bm.ReadyForQuery()) case fm.BindMsg: _, ok := s.portals[v.DestPortalName] // unnamed portal overrides previous if ok && v.DestPortalName != "" { - s.ErrorHandle(fmt.Errorf("portal %s already present", v.DestPortalName)) - waitForSync = true + waitForSync = extQueryMode + s.ErrorHandle(fmt.Errorf("portal '%s' already present", v.DestPortalName)) continue } st, ok := s.statements[v.PreparedStatementName] if !ok { - s.ErrorHandle(fmt.Errorf("statement %s not found", v.PreparedStatementName)) - waitForSync = true + waitForSync = extQueryMode + s.ErrorHandle(fmt.Errorf("statement '%s' not found", v.PreparedStatementName)) continue } encodedParams, err := buildNamedParams(st.Params, v.ParamVals) if err != nil { + waitForSync = extQueryMode s.ErrorHandle(err) - waitForSync = true + continue + } + + if _, err = s.writeMessage(bm.BindComplete()); err != nil { + waitForSync = extQueryMode continue } @@ -191,32 +228,36 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { Parameters: encodedParams, ResultColumnFormatCodes: v.ResultColumnFormatCodes, } - s.portals[v.DestPortalName] = newPortal - if _, err = s.writeMessage(bm.BindComplete()); err != nil { - s.ErrorHandle(err) - waitForSync = true - continue - } + s.portals[v.DestPortalName] = newPortal case fm.Execute: //query execution - if err = s.fetchAndWriteResults(ctx, s.portals[v.PortalName].Statement.SQLStatement, - s.portals[v.PortalName].Parameters, - s.portals[v.PortalName].ResultColumnFormatCodes, + portal, ok := s.portals[v.PortalName] + if !ok { + waitForSync = extQueryMode + s.ErrorHandle(fmt.Errorf("portal '%s' not found", v.PortalName)) + continue + } + + delete(s.portals, v.PortalName) + + if err = s.fetchAndWriteResults(ctx, portal.Statement.SQLStatement, + portal.Parameters, + portal.ResultColumnFormatCodes, true); err != nil { + waitForSync = extQueryMode s.ErrorHandle(err) - waitForSync = true continue } - if _, err := s.writeMessage(bm.CommandComplete([]byte(`ok`))); err != nil { - s.ErrorHandle(err) - waitForSync = true + + if _, err := s.writeMessage(bm.CommandComplete([]byte("ok"))); err != nil { + waitForSync = extQueryMode } case fm.FlushMsg: // there is no buffer to be flushed default: + waitForSync = extQueryMode s.ErrorHandle(pserr.ErrUnknowMessageType) - continue } } } @@ -225,17 +266,18 @@ func (s *session) fetchAndWriteResults(ctx context.Context, statements string, p if s.isInBlackList(statements) { return nil } + if i := s.isEmulableInternally(statements); i != nil { if err := s.tryToHandleInternally(i); err != nil && err != pserr.ErrMessageCannotBeHandledInternally { return err } - return nil } stmts, err := sql.Parse(strings.NewReader(statements)) if err != nil { return err } + for _, stmt := range stmts { switch st := stmt.(type) { case *sql.UseDatabaseStmt: @@ -256,6 +298,7 @@ func (s *session) fetchAndWriteResults(ctx context.Context, statements string, p } } } + return nil } @@ -310,27 +353,7 @@ type statement struct { Results []*schema.Column } -func (s *session) inferParamAndResultCols(ctx context.Context, statement string) ([]*schema.Column, []*schema.Column, error) { - // todo @Michele The query string contained in a Parse message cannot include more than one SQL statement; - // else a syntax error is reported. This restriction does not exist in the simple-query protocol, - // but it does exist in the extended protocol, because allowing prepared statements or portals to contain - // multiple commands would complicate the protocol unduly. - stmts, err := sql.Parse(strings.NewReader(statement)) - if err != nil { - return nil, nil, err - } - // The query string contained in a Parse message cannot include more than one SQL statement; - // else a syntax error is reported. This restriction does not exist in the simple-query protocol, but it does exist - // in the extended protocol, because allowing prepared statements or portals to contain multiple commands would - // complicate the protocol unduly. - if len(stmts) > 1 { - return nil, nil, pserr.ErrMaxStmtNumberExceeded - } - if len(stmts) == 0 { - return nil, nil, pserr.ErrNoStatementFound - } - stmt := stmts[0] - +func (s *session) inferParamAndResultCols(ctx context.Context, stmt sql.SQLStmt) ([]*schema.Column, []*schema.Column, error) { resCols := make([]*schema.Column, 0) sel, ok := stmt.(*sql.SelectStmt) From 5644dacaa522c9dda7d36c701d20e7b146b77728 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Thu, 26 Oct 2023 14:24:44 +0200 Subject: [PATCH 06/23] chore(pkg/pgsql): transactional query machine Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/errors/errors.go | 3 +- pkg/pgsql/server/initialize_session.go | 49 +++++++++---- pkg/pgsql/server/options.go | 40 +++++------ pkg/pgsql/server/query_machine.go | 90 +++++++++++------------- pkg/pgsql/server/query_machine_test.go | 5 +- pkg/pgsql/server/request_handler.go | 18 ++--- pkg/pgsql/server/request_handler_test.go | 51 -------------- pkg/pgsql/server/server.go | 57 ++++++++------- pkg/pgsql/server/server_test.go | 10 +-- pkg/pgsql/server/session.go | 89 +++++++++++------------ pkg/pgsql/server/session_factory.go | 39 ---------- pkg/pgsql/server/session_factory_test.go | 37 ---------- pkg/pgsql/server/ssl_handshake_test.go | 2 - 13 files changed, 183 insertions(+), 307 deletions(-) delete mode 100644 pkg/pgsql/server/request_handler_test.go delete mode 100644 pkg/pgsql/server/session_factory.go delete mode 100644 pkg/pgsql/server/session_factory_test.go diff --git a/pkg/pgsql/errors/errors.go b/pkg/pgsql/errors/errors.go index 0e9debaa6f..040026be47 100644 --- a/pkg/pgsql/errors/errors.go +++ b/pkg/pgsql/errors/errors.go @@ -31,8 +31,7 @@ var ErrPwNotprovided = errors.New("password not provided") var ErrDBNotExists = errors.New("selected db doesn't exists") var ErrUsernameNotFound = errors.New("user not found") var ErrExpectedQueryMessage = errors.New("expected query message") -var ErrUseDBStatementNotSupported = errors.New("SQL statement not supported. Please use `UseDatabase` operation instead") -var ErrCreateDBStatementNotSupported = errors.New("SQL statement not supported. Please use `CreateDatabase` operation instead") +var ErrUseDBStatementNotSupported = errors.New("SQL statement not supported") var ErrSSLNotSupported = errors.New("SSL not supported") var ErrMaxStmtNumberExceeded = errors.New("maximum number of statements in a single query exceeded") var ErrNoStatementFound = errors.New("no statement found") diff --git a/pkg/pgsql/server/initialize_session.go b/pkg/pgsql/server/initialize_session.go index ef328ed588..205e6b971f 100644 --- a/pkg/pgsql/server/initialize_session.go +++ b/pkg/pgsql/server/initialize_session.go @@ -19,23 +19,25 @@ package server import ( "bufio" "bytes" + "context" "encoding/binary" "errors" "fmt" - "strings" + "github.com/codenotary/immudb/pkg/client" "github.com/codenotary/immudb/pkg/database" pserr "github.com/codenotary/immudb/pkg/pgsql/errors" bm "github.com/codenotary/immudb/pkg/pgsql/server/bmessages" fm "github.com/codenotary/immudb/pkg/pgsql/server/fmessages" "github.com/codenotary/immudb/pkg/pgsql/server/pgmeta" + "google.golang.org/grpc/metadata" ) // InitializeSession func (s *session) InitializeSession() (err error) { defer func() { if err != nil { - s.ErrorHandle(err) + s.HandleError(err) s.mr.CloseConnection() } }() @@ -124,10 +126,10 @@ func (s *session) InitializeSession() (err error) { } // HandleStartup errors are returned and handled in the caller -func (s *session) HandleStartup(dbList database.DatabaseList) (err error) { +func (s *session) HandleStartup(ctx context.Context) (err error) { defer func() { if err != nil { - s.ErrorHandle(err) + s.HandleError(err) s.mr.CloseConnection() } }() @@ -136,51 +138,65 @@ func (s *session) HandleStartup(dbList database.DatabaseList) (err error) { if !ok || user == "" { return pserr.ErrUsernameNotprovided } - s.username = user + db, ok := s.connParams["database"] if !ok { return pserr.ErrDBNotprovided } - s.database, err = dbList.GetByName(db) + + s.db, err = s.dbList.GetByName(db) if err != nil { if errors.Is(err, database.ErrDatabaseNotExists) { return pserr.ErrDBNotExists } return err } - s.log.Debugf("selected %s database", s.database.GetName()) if _, err = s.writeMessage(bm.AuthenticationCleartextPassword()); err != nil { return err } + msg, _, err := s.nextMessage() if err != nil { return err } + if pw, ok := msg.(fm.PasswordMsg); ok { if !ok || pw.GetSecret() == "" { return pserr.ErrPwNotprovided } - usr, err := s.getUser([]byte(s.username)) + + opts := client.DefaultOptions(). + WithAddress(s.immudbHost). + WithPort(s.immudbPort). + WithDisableIdentityCheck(true) + + s.client = client.NewClient().WithOptions(opts) + + err := s.client.OpenSession(ctx, []byte(user), []byte(pw.GetSecret()), db) if err != nil { - if strings.Contains(err.Error(), "key not found") { - return pserr.ErrUsernameNotFound - } - } - if err := usr.ComparePasswords([]byte(pw.GetSecret())); err != nil { return err } - s.log.Debugf("authentication successful for %s", s.username) + + s.client.CurrentState(context.Background()) + + sessionID := s.client.GetSessionID() + s.ctx = metadata.NewIncomingContext(context.Background(), metadata.Pairs("sessionid", sessionID)) + + s.log.Debugf("authentication successful for %s", user) if _, err := s.writeMessage(bm.AuthenticationOk()); err != nil { return err } } + if _, err := s.writeMessage(bm.ParameterStatus([]byte("standard_conforming_strings"), []byte("on"))); err != nil { return err } + if _, err := s.writeMessage(bm.ParameterStatus([]byte("client_encoding"), []byte("UTF8"))); err != nil { return err } + // todo this is needed by jdbc driver. Here is added the minor supported version at the moment if _, err := s.writeMessage(bm.ParameterStatus([]byte("server_version"), []byte(pgmeta.PgsqlProtocolVersion))); err != nil { return err @@ -194,3 +210,8 @@ func parseProtocolVersion(payload []byte) string { minor := int(binary.BigEndian.Uint16(payload[2:4])) return fmt.Sprintf("%d.%d", major, minor) } + +func (s *session) Close() error { + s.mr.CloseConnection() + return s.client.CloseSession(s.ctx) +} diff --git a/pkg/pgsql/server/options.go b/pkg/pgsql/server/options.go index 91f45e33e7..6c0f9b5110 100644 --- a/pkg/pgsql/server/options.go +++ b/pkg/pgsql/server/options.go @@ -23,46 +23,40 @@ import ( "github.com/codenotary/immudb/pkg/database" ) -type Option func(s *srv) +type Option func(s *pgsrv) -func Address(addr string) Option { - return func(args *srv) { - args.Address = addr +func Host(host string) Option { + return func(args *pgsrv) { + args.host = host } } func Port(port int) Option { - return func(args *srv) { - args.Port = port + return func(args *pgsrv) { + args.port = port } } -func Logger(logger logger.Logger) Option { - return func(args *srv) { - args.Logger = logger +func ImmudbPort(port int) Option { + return func(args *pgsrv) { + args.immudbPort = port } } -func DatabaseList(dbList database.DatabaseList) Option { - return func(args *srv) { - args.dbList = dbList - } -} - -func SysDb(sysdb database.DB) Option { - return func(args *srv) { - args.sysDb = sysdb +func Logger(logger logger.Logger) Option { + return func(args *pgsrv) { + args.logger = logger } } -func TlsConfig(tlsConfig *tls.Config) Option { - return func(args *srv) { +func TLSConfig(tlsConfig *tls.Config) Option { + return func(args *pgsrv) { args.tlsConfig = tlsConfig } } -func SessFactory(sf SessionFactory) Option { - return func(args *srv) { - args.SessionFactory = sf +func DatabaseList(dbList database.DatabaseList) Option { + return func(args *pgsrv) { + args.dbList = dbList } } diff --git a/pkg/pgsql/server/query_machine.go b/pkg/pgsql/server/query_machine.go index c9d47b66ba..c2f721cc25 100644 --- a/pkg/pgsql/server/query_machine.go +++ b/pkg/pgsql/server/query_machine.go @@ -17,7 +17,6 @@ limitations under the License. package server import ( - "context" "errors" "fmt" "io" @@ -32,14 +31,11 @@ import ( fm "github.com/codenotary/immudb/pkg/pgsql/server/fmessages" ) -// QueriesMachine ... -func (s *session) QueriesMachine(ctx context.Context) (err error) { - s.Lock() - defer s.Unlock() - +func (s *session) QueryMachine() error { var waitForSync = false - if _, err = s.writeMessage(bm.ReadyForQuery()); err != nil { + _, err := s.writeMessage(bm.ReadyForQuery()) + if err != nil { return err } @@ -50,7 +46,7 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { s.log.Warningf("connection is closed") return nil } - s.ErrorHandle(err) + s.HandleError(err) continue } @@ -68,10 +64,10 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { case fm.TerminateMsg: return s.mr.CloseConnection() case fm.QueryMsg: - err := s.fetchAndWriteResults(ctx, v.GetStatements(), nil, nil, false) + err := s.fetchAndWriteResults(v.GetStatements(), nil, nil, false) if err != nil { waitForSync = extQueryMode - s.ErrorHandle(err) + s.HandleError(err) } if _, err = s.writeMessage(bm.ReadyForQuery()); err != nil { @@ -82,7 +78,7 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { // unnamed prepared statement overrides previous if ok && v.DestPreparedStatementName != "" { waitForSync = extQueryMode - s.ErrorHandle(fmt.Errorf("statement '%s' already present", v.DestPreparedStatementName)) + s.HandleError(fmt.Errorf("statement '%s' already present", v.DestPreparedStatementName)) continue } @@ -105,7 +101,7 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { stmts, err := sql.Parse(strings.NewReader(v.Statements)) if err != nil { waitForSync = extQueryMode - s.ErrorHandle(err) + s.HandleError(err) continue } @@ -115,18 +111,18 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { // complicate the protocol unduly. if len(stmts) > 1 { waitForSync = extQueryMode - s.ErrorHandle(pserr.ErrMaxStmtNumberExceeded) + s.HandleError(pserr.ErrMaxStmtNumberExceeded) continue } if len(stmts) == 0 { waitForSync = extQueryMode - s.ErrorHandle(pserr.ErrNoStatementFound) + s.HandleError(pserr.ErrNoStatementFound) continue } - if paramCols, resCols, err = s.inferParamAndResultCols(ctx, stmts[0]); err != nil { + if paramCols, resCols, err = s.inferParamAndResultCols(stmts[0]); err != nil { waitForSync = extQueryMode - s.ErrorHandle(err) + s.HandleError(err) continue } @@ -160,7 +156,7 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { st, ok := s.statements[v.Name] if !ok { waitForSync = extQueryMode - s.ErrorHandle(fmt.Errorf("statement '%s' not found", v.Name)) + s.HandleError(fmt.Errorf("statement '%s' not found", v.Name)) continue } @@ -182,7 +178,7 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { portal, ok := s.portals[v.Name] if !ok { waitForSync = extQueryMode - s.ErrorHandle(fmt.Errorf("portal '%s' not found", v.Name)) + s.HandleError(fmt.Errorf("portal '%s' not found", v.Name)) continue } @@ -199,21 +195,21 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { // unnamed portal overrides previous if ok && v.DestPortalName != "" { waitForSync = extQueryMode - s.ErrorHandle(fmt.Errorf("portal '%s' already present", v.DestPortalName)) + s.HandleError(fmt.Errorf("portal '%s' already present", v.DestPortalName)) continue } st, ok := s.statements[v.PreparedStatementName] if !ok { waitForSync = extQueryMode - s.ErrorHandle(fmt.Errorf("statement '%s' not found", v.PreparedStatementName)) + s.HandleError(fmt.Errorf("statement '%s' not found", v.PreparedStatementName)) continue } encodedParams, err := buildNamedParams(st.Params, v.ParamVals) if err != nil { waitForSync = extQueryMode - s.ErrorHandle(err) + s.HandleError(err) continue } @@ -235,18 +231,18 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { portal, ok := s.portals[v.PortalName] if !ok { waitForSync = extQueryMode - s.ErrorHandle(fmt.Errorf("portal '%s' not found", v.PortalName)) + s.HandleError(fmt.Errorf("portal '%s' not found", v.PortalName)) continue } delete(s.portals, v.PortalName) - if err = s.fetchAndWriteResults(ctx, portal.Statement.SQLStatement, + if err = s.fetchAndWriteResults(portal.Statement.SQLStatement, portal.Parameters, portal.ResultColumnFormatCodes, true); err != nil { waitForSync = extQueryMode - s.ErrorHandle(err) + s.HandleError(err) continue } @@ -257,12 +253,12 @@ func (s *session) QueriesMachine(ctx context.Context) (err error) { // there is no buffer to be flushed default: waitForSync = extQueryMode - s.ErrorHandle(pserr.ErrUnknowMessageType) + s.HandleError(pserr.ErrUnknowMessageType) } } } -func (s *session) fetchAndWriteResults(ctx context.Context, statements string, parameters []*schema.NamedParam, resultColumnFormatCodes []int16, skipRowDesc bool) error { +func (s *session) fetchAndWriteResults(statements string, parameters []*schema.NamedParam, resultColumnFormatCodes []int16, skipRowDesc bool) error { if s.isInBlackList(statements) { return nil } @@ -284,16 +280,12 @@ func (s *session) fetchAndWriteResults(ctx context.Context, statements string, p { return pserr.ErrUseDBStatementNotSupported } - case *sql.CreateDatabaseStmt: - { - return pserr.ErrCreateDBStatementNotSupported - } case *sql.SelectStmt: - if err = s.query(ctx, st, parameters, resultColumnFormatCodes, skipRowDesc); err != nil { + if err = s.query(st, parameters, resultColumnFormatCodes, skipRowDesc); err != nil { return err } - case sql.SQLStmt: - if err = s.exec(ctx, st, parameters, resultColumnFormatCodes, skipRowDesc); err != nil { + default: + if err = s.exec(st, parameters, resultColumnFormatCodes, skipRowDesc); err != nil { return err } } @@ -302,11 +294,12 @@ func (s *session) fetchAndWriteResults(ctx context.Context, statements string, p return nil } -func (s *session) query(ctx context.Context, st *sql.SelectStmt, parameters []*schema.NamedParam, resultColumnFormatCodes []int16, skipRowDesc bool) error { - res, err := s.database.SQLQueryPrepared(ctx, nil, st, parameters) +func (s *session) query(st *sql.SelectStmt, parameters []*schema.NamedParam, resultColumnFormatCodes []int16, skipRowDesc bool) error { + res, err := s.db.SQLQueryPrepared(s.ctx, s.tx, st, parameters) if err != nil { return err } + if res != nil && len(res.Rows) > 0 { if !skipRowDesc { if _, err = s.writeMessage(bm.RowDescription(res.Columns, nil)); err != nil { @@ -318,24 +311,27 @@ func (s *session) query(ctx context.Context, st *sql.SelectStmt, parameters []*s } return nil } - if _, err = s.writeMessage(bm.EmptyQueryResponse()); err != nil { - return err - } - return nil + + _, err = s.writeMessage(bm.EmptyQueryResponse()) + return err } -func (s *session) exec(ctx context.Context, st sql.SQLStmt, namedParams []*schema.NamedParam, resultColumnFormatCodes []int16, skipRowDesc bool) error { +func (s *session) exec(st sql.SQLStmt, namedParams []*schema.NamedParam, resultColumnFormatCodes []int16, skipRowDesc bool) error { params := make(map[string]interface{}, len(namedParams)) for _, p := range namedParams { params[p.Name] = schema.RawValue(p.Value) } - if _, _, err := s.database.SQLExecPrepared(ctx, nil, []sql.SQLStmt{st}, params); err != nil { + ntx, _, err := s.db.SQLExecPrepared(s.ctx, s.tx, []sql.SQLStmt{st}, params) + s.tx = ntx + + if err != nil { return err } - return nil + _, err = s.writeMessage(bm.EmptyQueryResponse()) + return err } type portal struct { @@ -353,16 +349,16 @@ type statement struct { Results []*schema.Column } -func (s *session) inferParamAndResultCols(ctx context.Context, stmt sql.SQLStmt) ([]*schema.Column, []*schema.Column, error) { +func (s *session) inferParamAndResultCols(stmt sql.SQLStmt) ([]*schema.Column, []*schema.Column, error) { resCols := make([]*schema.Column, 0) sel, ok := stmt.(*sql.SelectStmt) if ok { - rr, err := s.database.SQLQueryRowReader(ctx, nil, sel, nil) + rr, err := s.db.SQLQueryRowReader(s.ctx, s.tx, sel, nil) if err != nil { return nil, nil, err } - cols, err := rr.Columns(ctx) + cols, err := rr.Columns(s.ctx) if err != nil { return nil, nil, err } @@ -371,7 +367,7 @@ func (s *session) inferParamAndResultCols(ctx context.Context, stmt sql.SQLStmt) } } - r, err := s.database.InferParametersPrepared(ctx, nil, stmt) + r, err := s.db.InferParametersPrepared(s.ctx, s.tx, stmt) if err != nil { return nil, nil, err } @@ -381,7 +377,7 @@ func (s *session) inferParamAndResultCols(ctx context.Context, stmt sql.SQLStmt) } var paramsNameList []string - for n, _ := range r { + for n := range r { paramsNameList = append(paramsNameList, n) } sort.Strings(paramsNameList) diff --git a/pkg/pgsql/server/query_machine_test.go b/pkg/pgsql/server/query_machine_test.go index badca9f56e..7d6d78925c 100644 --- a/pkg/pgsql/server/query_machine_test.go +++ b/pkg/pgsql/server/query_machine_test.go @@ -17,12 +17,10 @@ limitations under the License. package server import ( - "context" "errors" "fmt" "net" "os" - "sync" "testing" "github.com/codenotary/immudb/embedded/logger" @@ -404,7 +402,6 @@ func TestSession_QueriesMachine(t *testing.T) { s := session{ log: logger.NewSimpleLogger("test", os.Stdout), mr: mr, - Mutex: sync.Mutex{}, statements: make(map[string]*statement), portals: make(map[string]*portal), } @@ -417,7 +414,7 @@ func TestSession_QueriesMachine(t *testing.T) { } go tt.in(c2) - err := s.QueriesMachine(context.Background()) + err := s.QueryMachine() require.Equal(t, tt.out, err) }) diff --git a/pkg/pgsql/server/request_handler.go b/pkg/pgsql/server/request_handler.go index fe3af376af..a3ef5b0eb9 100644 --- a/pkg/pgsql/server/request_handler.go +++ b/pkg/pgsql/server/request_handler.go @@ -21,24 +21,20 @@ import ( "net" ) -func (s *srv) handleRequest(conn net.Conn) (err error) { - ss := s.SessionFactory.NewSession(conn, s.Logger, s.sysDb, s.tlsConfig) +func (s *pgsrv) handleRequest(ctx context.Context, conn net.Conn) (err error) { + ss := s.newSession(conn) + defer ss.Close() - // initialize session err = ss.InitializeSession() if err != nil { return err } - // authentication - err = ss.HandleStartup(s.dbList) - if err != nil { - return err - } - // https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.5.7.4 - err = ss.QueriesMachine(context.Background()) + + err = ss.HandleStartup(ctx) if err != nil { return err } - return nil + // https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.5.7.4 + return ss.QueryMachine() } diff --git a/pkg/pgsql/server/request_handler_test.go b/pkg/pgsql/server/request_handler_test.go deleted file mode 100644 index abc3e3f126..0000000000 --- a/pkg/pgsql/server/request_handler_test.go +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2022 Codenotary Inc. All rights reserved. - -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, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "errors" - "net" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestHandleRequestNil(t *testing.T) { - s := NewSessionMock() - sf := NewSessionFactoryMock(s) - srv := New(SessFactory(sf)) - - c, _ := net.Pipe() - err := srv.handleRequest(c) - - require.NoError(t, err) -} - -func TestHandleRequestInitializeError(t *testing.T) { - s := NewSessionMock() - errInit := errors.New("init error") - s.InitializeSessionF = func() error { - return errInit - } - sf := NewSessionFactoryMock(s) - srv := New(SessFactory(sf)) - - c, _ := net.Pipe() - err := srv.handleRequest(c) - - require.ErrorIs(t, err, errInit) -} diff --git a/pkg/pgsql/server/server.go b/pkg/pgsql/server/server.go index d124f9d000..73fe293621 100644 --- a/pkg/pgsql/server/server.go +++ b/pkg/pgsql/server/server.go @@ -17,6 +17,7 @@ limitations under the License. package server import ( + "context" "crypto/tls" "errors" "fmt" @@ -29,95 +30,103 @@ import ( "golang.org/x/net/netutil" ) -type srv struct { +type pgsrv struct { m sync.RWMutex running bool maxConnections int tlsConfig *tls.Config - SessionFactory SessionFactory - Logger logger.Logger - Address string - Port int + logger logger.Logger + host string + port int + immudbPort int dbList database.DatabaseList - sysDb database.DB listener net.Listener } -type Server interface { +type PGSQLServer interface { Initialize() error Serve() error Stop() error GetPort() int } -func New(setters ...Option) *srv { - +func New(setters ...Option) *pgsrv { // Default Options - cli := &srv{ + srv := &pgsrv{ running: true, maxConnections: 1000, tlsConfig: &tls.Config{}, - SessionFactory: NewSessionFactory(), - Logger: logger.NewSimpleLogger("sqlSrv", os.Stderr), - Address: "", - Port: 5432, + logger: logger.NewSimpleLogger("pgsqlSrv", os.Stderr), + host: "0.0.0.0", + immudbPort: 3322, + port: 5432, } for _, setter := range setters { - setter(cli) + setter(srv) } - return cli + return srv } // Initialize initialize listener. If provided port is zero os auto assign a free one. -func (s *srv) Initialize() (err error) { - s.listener, err = net.Listen("tcp", fmt.Sprintf("%s:%d", s.Address, s.Port)) +func (s *pgsrv) Initialize() (err error) { + s.listener, err = net.Listen("tcp", fmt.Sprintf("%s:%d", s.host, s.port)) if err != nil { return err } return nil } -func (s *srv) Serve() (err error) { +func (s *pgsrv) Serve() (err error) { s.m.Lock() if s.listener == nil { return errors.New("no listener found for pgsql server") } - s.listener = netutil.LimitListener(s.listener, s.maxConnections) s.m.Unlock() for { s.m.Lock() if !s.running { + s.m.Unlock() return nil } s.m.Unlock() + conn, err := s.listener.Accept() if err != nil { - s.Logger.Errorf("%v", err) + s.logger.Errorf("%v", err) } else { - go s.handleRequest(conn) + go s.handleRequest(context.Background(), conn) } } } -func (s *srv) Stop() (err error) { +func (s *pgsrv) newSession(conn net.Conn) Session { + return newSession(conn, s.host, s.immudbPort, s.logger, s.tlsConfig, s.dbList) +} + +func (s *pgsrv) Stop() (err error) { s.m.Lock() defer s.m.Unlock() + s.running = false + if s.listener != nil { return s.listener.Close() } + return nil } -func (s *srv) GetPort() int { +func (s *pgsrv) GetPort() int { s.m.Lock() defer s.m.Unlock() + if s.listener != nil { return s.listener.Addr().(*net.TCPAddr).Port } + return 0 } diff --git a/pkg/pgsql/server/server_test.go b/pkg/pgsql/server/server_test.go index d99664d9fc..944b783515 100644 --- a/pkg/pgsql/server/server_test.go +++ b/pkg/pgsql/server/server_test.go @@ -23,27 +23,27 @@ import ( ) func TestSrv_Initialize(t *testing.T) { - s := srv{ - Port: 99999999999999999, + s := pgsrv{ + port: 99999999999999999, } err := s.Initialize() require.ErrorContains(t, err, "invalid port") } func TestSrv_GetPort(t *testing.T) { - s := srv{} + s := pgsrv{} err := s.GetPort() require.Equal(t, 0, err) } func TestSrv_Stop(t *testing.T) { - s := srv{} + s := pgsrv{} res := s.Stop() require.Nil(t, res) } func TestSrv_Serve(t *testing.T) { - s := srv{} + s := pgsrv{} err := s.Serve() require.ErrorContains(t, err, "no listener found for pgsql server") } diff --git a/pkg/pgsql/server/session.go b/pkg/pgsql/server/session.go index da71d146ca..37df42b662 100644 --- a/pkg/pgsql/server/session.go +++ b/pkg/pgsql/server/session.go @@ -19,13 +19,12 @@ package server import ( "context" "crypto/tls" - "encoding/json" + "net" - "sync" "github.com/codenotary/immudb/embedded/logger" - "github.com/codenotary/immudb/pkg/api/schema" - "github.com/codenotary/immudb/pkg/auth" + "github.com/codenotary/immudb/embedded/sql" + "github.com/codenotary/immudb/pkg/client" "github.com/codenotary/immudb/pkg/database" "github.com/codenotary/immudb/pkg/pgsql/errors" fm "github.com/codenotary/immudb/pkg/pgsql/server/fmessages" @@ -33,40 +32,54 @@ import ( ) type session struct { - tlsConfig *tls.Config - log logger.Logger - mr MessageReader - username string - database database.DB - sysDb database.DB + immudbHost string + immudbPort int + tlsConfig *tls.Config + log logger.Logger + + dbList database.DatabaseList + + client client.ImmuClient + + ctx context.Context + db database.DB + tx *sql.SQLTx + + mr MessageReader + connParams map[string]string protocolVersion string - portals map[string]*portal - statements map[string]*statement - sync.Mutex + + statements map[string]*statement + portals map[string]*portal } type Session interface { InitializeSession() error - HandleStartup(dbList database.DatabaseList) error - QueriesMachine(ctx context.Context) (err error) - ErrorHandle(err error) + HandleStartup(context.Context) error + QueryMachine() error + HandleError(error) + Close() error } -func NewSession(c net.Conn, log logger.Logger, sysDb database.DB, tlsConfig *tls.Config) *session { - s := &session{ +func newSession(c net.Conn, immudbHost string, immudbPort int, + log logger.Logger, tlsConfig *tls.Config, dbList database.DatabaseList) *session { + + return &session{ + immudbHost: immudbHost, + immudbPort: immudbPort, tlsConfig: tlsConfig, log: log, + dbList: dbList, mr: NewMessageReader(c), - sysDb: sysDb, - portals: make(map[string]*portal), statements: make(map[string]*statement), + portals: make(map[string]*portal), } - return s } -func (s *session) ErrorHandle(e error) { +func (s *session) HandleError(e error) { pgerr := errors.MapPgError(e) + _, err := s.writeMessage(pgerr.Encode()) if err != nil { s.log.Errorf("unable to write error on wire: %w", err) @@ -78,8 +91,11 @@ func (s *session) nextMessage() (interface{}, bool, error) { if err != nil { return nil, false, err } + s.log.Debugf("received %s - %s message", string(msg.t), pgmeta.MTypes[msg.t]) + extQueryMode := false + i, err := s.parseRawMessage(msg) if msg.t == 'P' || msg.t == 'B' || @@ -88,6 +104,7 @@ func (s *session) nextMessage() (interface{}, bool, error) { msg.t == 'H' { extQueryMode = true } + return i, extQueryMode, err } @@ -117,33 +134,9 @@ func (s *session) parseRawMessage(msg *rawMessage) (interface{}, error) { } func (s *session) writeMessage(msg []byte) (int, error) { - s.debugMessage(msg) - return s.mr.Write(msg) -} - -func (s *session) debugMessage(msg []byte) { - if s.log != nil && len(msg) > 0 { + if len(msg) > 0 { s.log.Debugf("write %s - %s message", string(msg[0]), pgmeta.MTypes[msg[0]]) } -} - -func (s *session) getUser(username []byte) (*auth.User, error) { - key := make([]byte, 1+len(username)) - // todo put KeyPrefixUser in a common package - key[0] = 1 - copy(key[1:], username) - - item, err := s.sysDb.Get(context.Background(), &schema.KeyRequest{Key: key}) - if err != nil { - return nil, err - } - var usr auth.User - - err = json.Unmarshal(item.Value, &usr) - if err != nil { - return nil, err - } - - return &usr, nil + return s.mr.Write(msg) } diff --git a/pkg/pgsql/server/session_factory.go b/pkg/pgsql/server/session_factory.go deleted file mode 100644 index 3658601fca..0000000000 --- a/pkg/pgsql/server/session_factory.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2022 Codenotary Inc. All rights reserved. - -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, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "crypto/tls" - "net" - - "github.com/codenotary/immudb/embedded/logger" - "github.com/codenotary/immudb/pkg/database" -) - -type sessionFactory struct{} - -type SessionFactory interface { - NewSession(conn net.Conn, log logger.Logger, sysDb database.DB, tlsConfig *tls.Config) Session -} - -func NewSessionFactory() sessionFactory { - return sessionFactory{} -} - -func (sm sessionFactory) NewSession(conn net.Conn, log logger.Logger, sysDb database.DB, tlsConfig *tls.Config) Session { - return NewSession(conn, log, sysDb, tlsConfig) -} diff --git a/pkg/pgsql/server/session_factory_test.go b/pkg/pgsql/server/session_factory_test.go deleted file mode 100644 index 3830e12f9d..0000000000 --- a/pkg/pgsql/server/session_factory_test.go +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright 2022 Codenotary Inc. All rights reserved. - -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, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "crypto/tls" - "net" - - "github.com/codenotary/immudb/embedded/logger" - "github.com/codenotary/immudb/pkg/database" -) - -type sessionFactoryMock struct { - s Session -} - -func NewSessionFactoryMock(s Session) sessionFactoryMock { - return sessionFactoryMock{s: s} -} - -func (sm sessionFactoryMock) NewSession(conn net.Conn, log logger.Logger, sysDb database.DB, tlsConfig *tls.Config) Session { - return sm.s -} diff --git a/pkg/pgsql/server/ssl_handshake_test.go b/pkg/pgsql/server/ssl_handshake_test.go index 38829514b5..40f5e07d06 100644 --- a/pkg/pgsql/server/ssl_handshake_test.go +++ b/pkg/pgsql/server/ssl_handshake_test.go @@ -21,7 +21,6 @@ import ( "io" "net" "os" - "sync" "testing" "github.com/codenotary/immudb/embedded/logger" @@ -69,7 +68,6 @@ EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA== s := session{ tlsConfig: cfg, mr: mr, - Mutex: sync.Mutex{}, log: logger.NewSimpleLogger("test", os.Stdout), } From cb413ea5d8523253736edc0b5db072d345a4dd19 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Thu, 26 Oct 2023 14:25:21 +0200 Subject: [PATCH 07/23] chore(cmd/immudb): upgrade to new pgsql changes Signed-off-by: Jeronimo Irazabal --- cmd/immudb/command/immudbcmdtest/immuServerMock.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/immudb/command/immudbcmdtest/immuServerMock.go b/cmd/immudb/command/immudbcmdtest/immuServerMock.go index 14ff133658..4ea6c99acd 100644 --- a/cmd/immudb/command/immudbcmdtest/immuServerMock.go +++ b/cmd/immudb/command/immudbcmdtest/immuServerMock.go @@ -29,11 +29,11 @@ type ImmuServerMock struct { Logger logger.Logger StateSigner server.StateSigner Ssf stream.ServiceFactory - PgsqlSrv pgsqlsrv.Server + PgsqlSrv pgsqlsrv.PGSQLServer DbList database.DatabaseList } -func (s *ImmuServerMock) WithPgsqlServer(psrv pgsqlsrv.Server) server.ImmuServerIf { +func (s *ImmuServerMock) WithPgsqlServer(psrv pgsqlsrv.PGSQLServer) server.ImmuServerIf { s.PgsqlSrv = psrv return s } From ce9ec827f9d3cf8072cb7a180dca0f325692b2b1 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Thu, 26 Oct 2023 14:25:48 +0200 Subject: [PATCH 08/23] chore(pkg/client): possibility to retrieve session id Signed-off-by: Jeronimo Irazabal --- pkg/client/client.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/client/client.go b/pkg/client/client.go index e31c91160a..b9f4efa1ad 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -100,6 +100,8 @@ type ImmuClient interface { // (without explicit call, the server will only free resources after session inactivity timeout). CloseSession(ctx context.Context) error + GetSessionID() string + // CreateUser creates new user with given credentials and permission. // // Required user permission is SysAdmin or database Admin. From 9e5886c0b7c283f3c8e1a09ea0b7b3e5c7a69d15 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Thu, 26 Oct 2023 14:26:23 +0200 Subject: [PATCH 09/23] chore(pkg/server): upgrade to transactional pgsql server Signed-off-by: Jeronimo Irazabal --- pkg/server/server.go | 9 ++++++++- pkg/server/types.go | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/server/server.go b/pkg/server/server.go index f129f9fc90..cd1676a64a 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -250,7 +250,14 @@ func (s *ImmuServer) Initialize() error { protomodel.RegisterAuthorizationServiceServer(s.GrpcServer, &authenticationServiceImp{server: s}) grpc_prometheus.Register(s.GrpcServer) - s.PgsqlSrv = pgsqlsrv.New(pgsqlsrv.Address(s.Options.Address), pgsqlsrv.Port(s.Options.PgsqlServerPort), pgsqlsrv.DatabaseList(s.dbList), pgsqlsrv.SysDb(s.sysDB), pgsqlsrv.TlsConfig(s.Options.TLSConfig), pgsqlsrv.Logger(s.Logger)) + s.PgsqlSrv = pgsqlsrv.New( + pgsqlsrv.Host(s.Options.Address), + pgsqlsrv.Port(s.Options.PgsqlServerPort), + pgsqlsrv.ImmudbPort(s.Options.Port), + pgsqlsrv.TLSConfig(s.Options.TLSConfig), + pgsqlsrv.Logger(s.Logger), + pgsqlsrv.DatabaseList(s.dbList), + ) if s.Options.PgsqlServer { if err = s.PgsqlSrv.Initialize(); err != nil { return err diff --git a/pkg/server/types.go b/pkg/server/types.go index a62f2e9389..1973a24ab3 100644 --- a/pkg/server/types.go +++ b/pkg/server/types.go @@ -81,7 +81,7 @@ type ImmuServer struct { pgsqlMux sync.Mutex StateSigner StateSigner StreamServiceFactory stream.ServiceFactory - PgsqlSrv pgsqlsrv.Server + PgsqlSrv pgsqlsrv.PGSQLServer remoteStorage remotestorage.Storage @@ -112,7 +112,7 @@ type ImmuServerIf interface { WithLogger(logger.Logger) ImmuServerIf WithStateSigner(stateSigner StateSigner) ImmuServerIf WithStreamServiceFactory(ssf stream.ServiceFactory) ImmuServerIf - WithPgsqlServer(psrv pgsqlsrv.Server) ImmuServerIf + WithPgsqlServer(psrv pgsqlsrv.PGSQLServer) ImmuServerIf WithDbList(dbList database.DatabaseList) ImmuServerIf } @@ -140,7 +140,7 @@ func (s *ImmuServer) WithOptions(options *Options) ImmuServerIf { } // WithPgsqlServer ... -func (s *ImmuServer) WithPgsqlServer(psrv pgsqlsrv.Server) ImmuServerIf { +func (s *ImmuServer) WithPgsqlServer(psrv pgsqlsrv.PGSQLServer) ImmuServerIf { s.PgsqlSrv = psrv return s } From f9fcb17ae410b41e20fd43f8d6df359da9a3295a Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Thu, 26 Oct 2023 15:41:06 +0200 Subject: [PATCH 10/23] chore(pkg/pgsql): proper handling of queries with empty resultsets Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/query_machine.go | 48 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/pkg/pgsql/server/query_machine.go b/pkg/pgsql/server/query_machine.go index c2f721cc25..276b9d2f8f 100644 --- a/pkg/pgsql/server/query_machine.go +++ b/pkg/pgsql/server/query_machine.go @@ -64,7 +64,7 @@ func (s *session) QueryMachine() error { case fm.TerminateMsg: return s.mr.CloseConnection() case fm.QueryMsg: - err := s.fetchAndWriteResults(v.GetStatements(), nil, nil, false) + err := s.fetchAndWriteResults(v.GetStatements(), nil, nil, extQueryMode) if err != nil { waitForSync = extQueryMode s.HandleError(err) @@ -237,17 +237,14 @@ func (s *session) QueryMachine() error { delete(s.portals, v.PortalName) - if err = s.fetchAndWriteResults(portal.Statement.SQLStatement, + err := s.fetchAndWriteResults(portal.Statement.SQLStatement, portal.Parameters, portal.ResultColumnFormatCodes, - true); err != nil { + extQueryMode, + ) + if err != nil { waitForSync = extQueryMode s.HandleError(err) - continue - } - - if _, err := s.writeMessage(bm.CommandComplete([]byte("ok"))); err != nil { - waitForSync = extQueryMode } case fm.FlushMsg: // there is no buffer to be flushed @@ -258,7 +255,12 @@ func (s *session) QueryMachine() error { } } -func (s *session) fetchAndWriteResults(statements string, parameters []*schema.NamedParam, resultColumnFormatCodes []int16, skipRowDesc bool) error { +func (s *session) fetchAndWriteResults(statements string, parameters []*schema.NamedParam, resultColumnFormatCodes []int16, extQueryMode bool) error { + if len(statements) == 0 { + _, err := s.writeMessage(bm.EmptyQueryResponse()) + return err + } + if s.isInBlackList(statements) { return nil } @@ -281,11 +283,18 @@ func (s *session) fetchAndWriteResults(statements string, parameters []*schema.N return pserr.ErrUseDBStatementNotSupported } case *sql.SelectStmt: - if err = s.query(st, parameters, resultColumnFormatCodes, skipRowDesc); err != nil { + if err = s.query(st, parameters, resultColumnFormatCodes, extQueryMode); err != nil { return err } default: - if err = s.exec(st, parameters, resultColumnFormatCodes, skipRowDesc); err != nil { + if err = s.exec(st, parameters, resultColumnFormatCodes, extQueryMode); err != nil { + return err + } + } + + if extQueryMode { + _, err = s.writeMessage(bm.CommandComplete([]byte("ok"))) + if err != nil { return err } } @@ -300,19 +309,13 @@ func (s *session) query(st *sql.SelectStmt, parameters []*schema.NamedParam, res return err } - if res != nil && len(res.Rows) > 0 { - if !skipRowDesc { - if _, err = s.writeMessage(bm.RowDescription(res.Columns, nil)); err != nil { - return err - } - } - if _, err = s.writeMessage(bm.DataRow(res.Rows, len(res.Columns), resultColumnFormatCodes)); err != nil { + if !skipRowDesc { + if _, err = s.writeMessage(bm.RowDescription(res.Columns, nil)); err != nil { return err } - return nil } - _, err = s.writeMessage(bm.EmptyQueryResponse()) + _, err = s.writeMessage(bm.DataRow(res.Rows, len(res.Columns), resultColumnFormatCodes)) return err } @@ -326,11 +329,6 @@ func (s *session) exec(st sql.SQLStmt, namedParams []*schema.NamedParam, resultC ntx, _, err := s.db.SQLExecPrepared(s.ctx, s.tx, []sql.SQLStmt{st}, params) s.tx = ntx - if err != nil { - return err - } - - _, err = s.writeMessage(bm.EmptyQueryResponse()) return err } From 5be79ffd403695a2f0a92ea4aea06351d4f6ddf6 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 27 Oct 2023 09:55:08 +0200 Subject: [PATCH 11/23] chore(pkg/pgsql): support multiple-statements in simple-query mode Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/query_machine.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pkg/pgsql/server/query_machine.go b/pkg/pgsql/server/query_machine.go index 276b9d2f8f..3661340ee9 100644 --- a/pkg/pgsql/server/query_machine.go +++ b/pkg/pgsql/server/query_machine.go @@ -292,11 +292,9 @@ func (s *session) fetchAndWriteResults(statements string, parameters []*schema.N } } - if extQueryMode { - _, err = s.writeMessage(bm.CommandComplete([]byte("ok"))) - if err != nil { - return err - } + _, err = s.writeMessage(bm.CommandComplete([]byte("ok"))) + if err != nil { + return err } } From 81c979406a3434cbc28b799091a5d304cf08e60e Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 27 Oct 2023 09:59:41 +0200 Subject: [PATCH 12/23] chore(pkg/pgsql): comment describing pgsql wire protocol constraints Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/query_machine.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/pgsql/server/query_machine.go b/pkg/pgsql/server/query_machine.go index 3661340ee9..ea6238f14e 100644 --- a/pkg/pgsql/server/query_machine.go +++ b/pkg/pgsql/server/query_machine.go @@ -94,10 +94,6 @@ func (s *session) QueryMachine() error { continue } - // todo @Michele The query string contained in a Parse message cannot include more than one SQL statement; - // else a syntax error is reported. This restriction does not exist in the simple-query protocol, - // but it does exist in the extended protocol, because allowing prepared statements or portals to contain - // multiple commands would complicate the protocol unduly. stmts, err := sql.Parse(strings.NewReader(v.Statements)) if err != nil { waitForSync = extQueryMode @@ -105,7 +101,7 @@ func (s *session) QueryMachine() error { continue } - // The query string contained in a Parse message cannot include more than one SQL statement; + // Note: as stated in the pgsql spec, the query string contained in a Parse message cannot include more than one SQL statement; // else a syntax error is reported. This restriction does not exist in the simple-query protocol, but it does exist // in the extended protocol, because allowing prepared statements or portals to contain multiple commands would // complicate the protocol unduly. From 5da2ae7d29f20d632d157902d2cce0e4e91a158b Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 27 Oct 2023 10:19:59 +0200 Subject: [PATCH 13/23] feat(embedded/sql): show databases/tables stmt Signed-off-by: Jeronimo Irazabal --- embedded/sql/parser.go | 3 + embedded/sql/sql_grammar.y | 15 + embedded/sql/sql_parser.go | 559 +++++++++++++++++++------------------ 3 files changed, 308 insertions(+), 269 deletions(-) diff --git a/embedded/sql/parser.go b/embedded/sql/parser.go index 1ffe4b0ce1..4855c6a617 100644 --- a/embedded/sql/parser.go +++ b/embedded/sql/parser.go @@ -92,6 +92,9 @@ var reservedWords = map[string]int{ "IS": IS, "CAST": CAST, "::": SCAST, + "SHOW": SHOW, + "DATABASES": DATABASES, + "TABLES": TABLES, } var joinTypes = map[string]JoinType{ diff --git a/embedded/sql/sql_grammar.y b/embedded/sql/sql_grammar.y index eb78b008e5..63b8badca5 100644 --- a/embedded/sql/sql_grammar.y +++ b/embedded/sql/sql_grammar.y @@ -75,6 +75,7 @@ func setResult(l yyLexer, stmts []SQLStmt) { %token SELECT DISTINCT FROM JOIN HAVING WHERE GROUP BY LIMIT OFFSET ORDER ASC DESC AS UNION ALL %token NOT LIKE IF EXISTS IN IS %token AUTO_INCREMENT NULL CAST SCAST +%token SHOW DATABASES TABLES %token NPARAM %token PPARAM %token JOINTYPE @@ -523,6 +524,20 @@ dqlstmt: right: $4.(DataSource), } } +| + SHOW DATABASES + { + $$ = &SelectStmt{ + ds: &FnDataSourceStmt{fnCall: &FnCall{fn: "databases"}}, + } + } +| + SHOW TABLES + { + $$ = &SelectStmt{ + ds: &FnDataSourceStmt{fnCall: &FnCall{fn: "tables"}}, + } + } select_stmt: SELECT opt_distinct opt_selectors FROM ds opt_indexon opt_joins opt_where opt_groupby opt_having opt_orderby opt_limit opt_offset { diff --git a/embedded/sql/sql_parser.go b/embedded/sql/sql_parser.go index 069d296943..c5ec1dc80f 100644 --- a/embedded/sql/sql_parser.go +++ b/embedded/sql/sql_parser.go @@ -119,22 +119,25 @@ const AUTO_INCREMENT = 57406 const NULL = 57407 const CAST = 57408 const SCAST = 57409 -const NPARAM = 57410 -const PPARAM = 57411 -const JOINTYPE = 57412 -const LOP = 57413 -const CMPOP = 57414 -const IDENTIFIER = 57415 -const TYPE = 57416 -const INTEGER = 57417 -const FLOAT = 57418 -const VARCHAR = 57419 -const BOOLEAN = 57420 -const BLOB = 57421 -const AGGREGATE_FUNC = 57422 -const ERROR = 57423 -const DOT = 57424 -const STMT_SEPARATOR = 57425 +const SHOW = 57410 +const DATABASES = 57411 +const TABLES = 57412 +const NPARAM = 57413 +const PPARAM = 57414 +const JOINTYPE = 57415 +const LOP = 57416 +const CMPOP = 57417 +const IDENTIFIER = 57418 +const TYPE = 57419 +const INTEGER = 57420 +const FLOAT = 57421 +const VARCHAR = 57422 +const BOOLEAN = 57423 +const BLOB = 57424 +const AGGREGATE_FUNC = 57425 +const ERROR = 57426 +const DOT = 57427 +const STMT_SEPARATOR = 57428 var yyToknames = [...]string{ "$end", @@ -204,6 +207,9 @@ var yyToknames = [...]string{ "NULL", "CAST", "SCAST", + "SHOW", + "DATABASES", + "TABLES", "NPARAM", "PPARAM", "JOINTYPE", @@ -242,109 +248,110 @@ var yyExca = [...]int16{ -1, 1, 1, -1, -2, 0, - -1, 80, - 59, 146, - 62, 146, - -2, 134, - -1, 205, - 45, 110, - -2, 105, - -1, 236, - 45, 110, + -1, 83, + 59, 148, + 62, 148, + -2, 136, + -1, 208, + 45, 112, -2, 107, + -1, 239, + 45, 112, + -2, 109, } const yyPrivate = 57344 -const yyLast = 405 +const yyLast = 411 var yyAct = [...]int16{ - 79, 320, 66, 199, 115, 229, 153, 255, 259, 94, - 159, 150, 188, 235, 107, 254, 6, 189, 170, 48, - 85, 110, 291, 246, 197, 245, 223, 197, 19, 197, - 197, 197, 296, 302, 276, 274, 295, 247, 224, 198, - 292, 260, 286, 277, 82, 275, 240, 84, 222, 78, - 163, 97, 93, 220, 95, 96, 212, 211, 261, 98, - 65, 88, 89, 90, 91, 92, 67, 161, 133, 196, - 119, 83, 256, 219, 216, 142, 87, 112, 142, 126, - 172, 143, 141, 137, 138, 139, 121, 118, 140, 127, - 128, 130, 129, 82, 106, 21, 84, 105, 280, 319, - 97, 93, 313, 95, 96, 279, 68, 223, 98, 155, - 88, 89, 90, 91, 92, 67, 108, 133, 152, 166, - 83, 167, 133, 162, 156, 87, 132, 213, 174, 175, - 176, 177, 178, 179, 197, 164, 114, 68, 127, 128, - 130, 129, 187, 190, 67, 130, 129, 119, 101, 133, - 63, 273, 157, 68, 272, 191, 185, 131, 132, 204, - 67, 279, 251, 202, 192, 242, 205, 209, 214, 210, - 127, 128, 130, 129, 117, 77, 184, 186, 207, 203, - 206, 53, 68, 218, 215, 151, 221, 28, 29, 267, - 253, 227, 116, 111, 133, 195, 194, 193, 171, 173, - 168, 231, 131, 132, 120, 165, 233, 144, 122, 100, - 71, 239, 171, 69, 37, 127, 128, 130, 129, 55, - 190, 52, 47, 158, 252, 238, 136, 99, 248, 290, - 217, 258, 243, 289, 54, 135, 249, 250, 133, 262, - 133, 271, 43, 70, 257, 266, 131, 132, 270, 263, - 264, 124, 125, 27, 61, 182, 181, 190, 183, 127, - 128, 130, 129, 180, 38, 321, 322, 305, 230, 281, - 200, 312, 299, 282, 284, 162, 285, 287, 108, 42, - 298, 265, 113, 35, 40, 208, 19, 293, 310, 303, - 294, 301, 300, 59, 228, 226, 22, 34, 33, 306, - 268, 225, 308, 148, 44, 45, 146, 147, 311, 145, - 314, 309, 232, 123, 72, 317, 318, 315, 19, 201, - 82, 2, 323, 84, 46, 324, 73, 97, 93, 32, - 95, 96, 10, 12, 11, 98, 104, 88, 89, 90, - 91, 92, 67, 41, 160, 241, 30, 83, 31, 13, - 76, 75, 87, 102, 103, 154, 7, 23, 8, 9, - 14, 15, 36, 20, 16, 17, 278, 24, 26, 25, - 19, 50, 51, 109, 134, 269, 288, 304, 56, 57, - 58, 316, 244, 283, 81, 80, 297, 237, 236, 234, - 74, 49, 60, 39, 64, 62, 86, 307, 149, 169, - 18, 5, 4, 3, 1, + 82, 323, 69, 202, 118, 232, 156, 258, 262, 97, + 162, 153, 191, 238, 110, 257, 6, 192, 173, 51, + 88, 113, 294, 249, 200, 248, 226, 200, 20, 305, + 200, 200, 299, 200, 279, 277, 298, 81, 250, 227, + 295, 201, 263, 289, 85, 280, 278, 87, 243, 225, + 223, 100, 96, 166, 19, 215, 214, 98, 99, 264, + 22, 199, 101, 68, 91, 92, 93, 94, 95, 70, + 164, 259, 222, 219, 86, 145, 175, 122, 146, 90, + 115, 85, 129, 136, 87, 145, 140, 141, 100, 96, + 144, 143, 142, 124, 98, 99, 121, 109, 108, 101, + 322, 91, 92, 93, 94, 95, 70, 130, 131, 133, + 132, 86, 158, 136, 283, 316, 90, 136, 282, 226, + 216, 155, 111, 200, 170, 136, 165, 159, 134, 135, + 117, 177, 178, 179, 180, 181, 182, 135, 167, 133, + 132, 130, 131, 133, 132, 190, 193, 71, 189, 130, + 131, 133, 132, 122, 70, 71, 71, 104, 194, 188, + 66, 160, 207, 70, 276, 275, 205, 195, 169, 208, + 212, 85, 213, 254, 87, 80, 245, 217, 100, 96, + 282, 210, 206, 209, 98, 99, 221, 218, 187, 101, + 120, 91, 92, 93, 94, 95, 70, 29, 30, 71, + 154, 86, 270, 256, 234, 56, 90, 230, 114, 236, + 198, 119, 197, 196, 242, 174, 176, 171, 168, 147, + 125, 103, 74, 193, 224, 72, 174, 255, 38, 58, + 102, 251, 136, 55, 261, 246, 50, 161, 136, 252, + 253, 241, 265, 134, 135, 40, 41, 260, 269, 134, + 135, 211, 266, 267, 127, 128, 130, 131, 133, 132, + 193, 57, 130, 131, 133, 132, 28, 20, 139, 293, + 220, 292, 284, 123, 274, 184, 285, 138, 165, 288, + 290, 273, 183, 136, 20, 185, 73, 46, 186, 64, + 296, 39, 308, 19, 304, 303, 324, 325, 233, 203, + 45, 315, 309, 302, 287, 311, 10, 12, 11, 111, + 19, 314, 301, 317, 268, 116, 36, 43, 320, 321, + 318, 313, 306, 13, 163, 326, 47, 48, 327, 297, + 7, 62, 8, 9, 14, 15, 231, 35, 16, 17, + 229, 34, 37, 23, 20, 271, 149, 150, 151, 148, + 76, 107, 228, 2, 24, 312, 235, 126, 75, 59, + 60, 61, 204, 49, 25, 27, 26, 33, 105, 106, + 19, 31, 244, 32, 79, 78, 44, 53, 54, 157, + 21, 281, 112, 137, 272, 291, 307, 319, 247, 286, + 84, 83, 300, 240, 239, 237, 77, 52, 63, 42, + 67, 65, 89, 310, 152, 172, 18, 5, 4, 3, + 1, } var yyPact = [...]int16{ - 328, -1000, -1000, 6, -1000, -1000, -1000, 267, -1000, -1000, - 350, 180, 329, 312, 264, 263, 239, 141, 208, 241, - -1000, 328, -1000, 182, 182, 182, 305, -1000, 149, 361, - 148, 161, 146, 141, 141, 141, 255, -1000, 197, 64, - -1000, -1000, 140, 185, 137, 294, 182, -1000, -1000, 338, - 35, 35, -1000, 136, 66, 331, 7, 4, 231, 120, - 244, -1000, 238, -1000, 53, 119, -1000, -3, 65, -1000, - 143, -4, 135, 293, -1000, 35, 35, -1000, 262, 175, - 168, -1000, 262, 262, -5, -1000, -1000, 262, -1000, -1000, - -1000, -1000, -1000, -8, -1000, -1000, -1000, -1000, -12, -1000, - -9, 134, 284, 282, 278, 112, 112, 349, 262, 69, - -1000, 151, -1000, -23, 80, -1000, -1000, 132, 33, 127, - -1000, 125, -10, 126, -1000, -1000, 175, 262, 262, 262, - 262, 262, 262, 198, 196, 102, -1000, 54, 59, 244, - 86, 262, 262, 112, -1000, 125, 124, 123, 122, -22, - 51, -1000, -52, 220, 300, 175, 349, 120, 262, 349, - 361, 276, 119, -15, 119, -1000, -34, -35, -1000, 44, - -1000, 94, 112, -16, 59, 59, 177, 177, 54, 5, - -1000, 165, 262, -17, -1000, -38, -1000, 131, -43, 24, - 175, -53, -1000, -1000, 277, -1000, 260, 118, 259, 217, - 262, 292, 220, -1000, 175, 155, 119, -45, 330, -1000, - -1000, -1000, -1000, 139, -67, -54, 112, -1000, 54, -14, - -1000, 88, -1000, 262, -1000, 117, -18, -1000, -18, -1000, - 262, 175, -32, 217, 231, -1000, 155, 236, -1000, -1000, - 119, 116, 273, -1000, 183, 79, 76, -1000, -56, -46, - -57, -48, 175, -1000, 78, -1000, 262, 22, 175, -1000, - -1000, 112, -1000, 226, -1000, -23, -1000, -49, -32, 169, - -1000, 164, -71, -51, -1000, -1000, -1000, -1000, -1000, -18, - 251, -55, -59, 234, 223, 349, 119, -58, -1000, -1000, - -1000, -1000, -1000, -1000, 249, -1000, -1000, 215, 262, 109, - 291, -1000, -1000, 247, 220, 222, 175, 19, -1000, 262, - -1000, 217, 109, 109, 175, -1000, 16, 212, -1000, 109, - -1000, -1000, -1000, 212, -1000, + 302, -1000, -1000, -32, -1000, -1000, -1000, 314, -1000, -1000, + 347, 190, 354, 350, 307, 303, 272, 152, 235, 176, + 274, -1000, 302, -1000, 227, 227, 227, 344, -1000, 160, + 367, 157, 185, 153, 152, 152, 152, 293, -1000, 232, + -1000, -1000, 71, -1000, -1000, 149, 228, 146, 338, 227, + -1000, -1000, 362, 23, 23, -1000, 145, 72, 346, 5, + 4, 262, 132, 225, -1000, 271, -1000, 44, 135, -1000, + 3, 68, -1000, 212, 0, 144, 337, -1000, 23, 23, + -1000, 113, 175, 210, -1000, 113, 113, -1, -1000, -1000, + 113, -1000, -1000, -1000, -1000, -1000, -3, -1000, -1000, -1000, + -1000, -8, -1000, -15, 143, 324, 322, 323, 124, 124, + 373, 113, 75, -1000, 162, -1000, -23, 80, -1000, -1000, + 142, 79, 141, -1000, 139, -17, 140, -1000, -1000, 175, + 113, 113, 113, 113, 113, 113, 217, 226, 111, -1000, + 62, 50, 225, 54, 113, 113, 124, -1000, 139, 137, + 136, 134, -33, 37, -1000, -53, 249, 343, 175, 373, + 132, 113, 373, 367, 242, 135, -18, 135, -1000, -38, + -39, -1000, 34, -1000, 100, 124, -20, 50, 50, 220, + 220, 62, 20, -1000, 205, 113, -21, -1000, -44, -1000, + 169, -45, 33, 175, -55, -1000, -1000, 328, -1000, 305, + 131, 301, 247, 113, 336, 249, -1000, 175, 168, 135, + -46, 357, -1000, -1000, -1000, -1000, 150, -70, -56, 124, + -1000, 62, -14, -1000, 96, -1000, 113, -1000, 127, -22, + -1000, -22, -1000, 113, 175, -34, 247, 262, -1000, 168, + 269, -1000, -1000, 135, 126, 318, -1000, 216, 87, 86, + -1000, -59, -48, -60, -49, 175, -1000, 94, -1000, 113, + 32, 175, -1000, -1000, 124, -1000, 256, -1000, -23, -1000, + -51, -34, 207, -1000, 204, -74, -54, -1000, -1000, -1000, + -1000, -1000, -22, 290, -58, -62, 266, 254, 373, 135, + -65, -1000, -1000, -1000, -1000, -1000, -1000, 282, -1000, -1000, + 240, 113, 123, 335, -1000, -1000, 280, 249, 252, 175, + 29, -1000, 113, -1000, 247, 123, 123, 175, -1000, 14, + 243, -1000, 123, -1000, -1000, -1000, 243, -1000, } var yyPgo = [...]int16{ - 0, 404, 321, 403, 402, 401, 16, 400, 399, 18, - 11, 8, 398, 397, 15, 7, 17, 12, 396, 9, - 20, 395, 394, 2, 393, 392, 10, 344, 19, 391, - 390, 175, 389, 13, 388, 387, 0, 14, 386, 385, - 384, 383, 3, 5, 382, 4, 381, 377, 1, 6, - 279, 376, 375, 374, 21, 373, 366, 363, + 0, 410, 353, 409, 408, 407, 16, 406, 405, 18, + 11, 8, 404, 403, 15, 7, 17, 12, 402, 9, + 20, 401, 400, 2, 399, 398, 10, 324, 19, 397, + 396, 175, 395, 13, 394, 393, 0, 14, 392, 391, + 390, 389, 3, 5, 388, 4, 387, 386, 1, 6, + 300, 385, 384, 383, 21, 382, 381, 380, } var yyR1 = [...]int8{ @@ -355,15 +362,15 @@ var yyR1 = [...]int8{ 12, 12, 14, 14, 15, 10, 10, 13, 13, 17, 17, 16, 16, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 8, 8, 9, 44, 44, 44, - 51, 51, 52, 52, 52, 6, 6, 7, 25, 25, - 24, 24, 21, 21, 22, 22, 20, 20, 20, 23, - 23, 26, 26, 26, 26, 27, 28, 29, 29, 29, - 30, 30, 30, 31, 31, 32, 32, 33, 33, 34, - 35, 35, 37, 37, 41, 41, 38, 38, 42, 42, - 43, 43, 47, 47, 49, 49, 46, 46, 48, 48, - 48, 45, 45, 45, 36, 36, 36, 36, 36, 36, - 36, 36, 39, 39, 39, 39, 53, 53, 40, 40, - 40, 40, 40, 40, 40, 40, + 51, 51, 52, 52, 52, 6, 6, 6, 6, 7, + 25, 25, 24, 24, 21, 21, 22, 22, 20, 20, + 20, 23, 23, 26, 26, 26, 26, 27, 28, 29, + 29, 29, 30, 30, 30, 31, 31, 32, 32, 33, + 33, 34, 35, 35, 37, 37, 41, 41, 38, 38, + 42, 42, 43, 43, 47, 47, 49, 49, 46, 46, + 48, 48, 48, 45, 45, 45, 36, 36, 36, 36, + 36, 36, 36, 36, 39, 39, 39, 39, 53, 53, + 40, 40, 40, 40, 40, 40, 40, 40, } var yyR2 = [...]int8{ @@ -374,87 +381,87 @@ var yyR2 = [...]int8{ 0, 1, 1, 3, 3, 1, 3, 1, 3, 0, 1, 1, 3, 1, 1, 1, 1, 1, 6, 1, 1, 1, 1, 4, 1, 3, 5, 0, 3, 3, - 0, 1, 0, 1, 2, 1, 4, 13, 0, 1, - 0, 1, 1, 1, 2, 4, 1, 4, 4, 1, - 3, 3, 4, 2, 6, 1, 2, 0, 2, 2, - 0, 2, 2, 2, 1, 0, 1, 1, 2, 6, - 0, 1, 0, 2, 0, 3, 0, 2, 0, 2, - 0, 2, 0, 3, 0, 4, 2, 4, 0, 1, - 1, 0, 1, 2, 1, 1, 2, 2, 4, 4, - 6, 6, 1, 1, 3, 3, 0, 1, 3, 3, - 3, 3, 3, 3, 3, 4, + 0, 1, 0, 1, 2, 1, 4, 2, 2, 13, + 0, 1, 0, 1, 1, 1, 2, 4, 1, 4, + 4, 1, 3, 3, 4, 2, 6, 1, 2, 0, + 2, 2, 0, 2, 2, 2, 1, 0, 1, 1, + 2, 6, 0, 1, 0, 2, 0, 3, 0, 2, + 0, 2, 0, 2, 0, 3, 0, 4, 2, 4, + 0, 1, 1, 0, 1, 2, 1, 1, 2, 2, + 4, 4, 6, 6, 1, 1, 3, 3, 0, 1, + 3, 3, 3, 3, 3, 3, 3, 4, } var yyChk = [...]int16{ -1000, -1, -2, -3, -4, -5, -6, 28, 30, 31, - 4, 6, 5, 21, 32, 33, 36, 37, -7, 42, - -57, 89, 29, 7, 17, 19, 18, 73, 7, 8, - 17, 19, 17, 34, 34, 44, -27, 73, 56, -24, - 43, -2, -50, 60, -50, -50, 19, 73, -28, -29, - 10, 11, 73, 20, 73, 73, -27, -27, -27, 38, - -25, 57, -21, 86, -22, -20, -23, 80, 73, 73, - 58, 73, 20, -50, -30, 13, 12, -31, 14, -36, - -39, -40, 58, 85, 61, -20, -18, 90, 75, 76, - 77, 78, 79, 66, -19, 68, 69, 65, 73, -31, - 73, 82, 22, 23, 5, 90, 90, -37, 47, -55, - -54, 73, -6, 44, 83, -45, 73, 55, 90, 82, - 61, 90, 73, 20, -31, -31, -36, 84, 85, 87, - 86, 71, 72, 63, -53, 67, 58, -36, -36, 90, - -36, 90, 90, 90, 73, 25, 24, 25, 25, -12, - -10, 73, -10, -49, 6, -36, -37, 83, 72, -26, - -27, 90, -19, 73, -20, 73, 86, -23, 73, -8, - -9, 73, 90, 73, -36, -36, -36, -36, -36, -36, - 65, 58, 59, 62, 74, -6, 91, -36, -17, -16, - -36, -10, -9, 73, 73, 73, 91, 83, 91, -42, - 50, 19, -49, -54, -36, -49, -28, -6, 9, -45, - -45, 91, 91, 83, 74, -10, 90, 65, -36, 90, - 91, 55, 91, 83, 91, 24, 35, 73, 35, -43, - 51, -36, 20, -42, -32, -33, -34, -35, 70, -45, - 91, 15, 26, -9, -44, 92, 90, 91, -10, -6, - -16, 74, -36, 73, -14, -15, 90, -14, -36, -11, - 73, 90, -43, -37, -33, 45, -45, 73, 27, -52, - 65, 58, 75, 75, 91, 91, 91, 91, -56, 83, - 20, -17, -10, -41, 48, -26, 91, -11, -51, 64, - 65, 93, 91, -15, 39, 91, 91, -38, 46, 49, - -49, -45, 91, 40, -47, 52, -36, -13, -23, 20, - 41, -42, 49, 83, -36, -43, -46, -23, -23, 83, - -48, 53, 54, -23, -48, + 4, 6, 5, 21, 32, 33, 36, 37, -7, 68, + 42, -57, 92, 29, 7, 17, 19, 18, 76, 7, + 8, 17, 19, 17, 34, 34, 44, -27, 76, 56, + 69, 70, -24, 43, -2, -50, 60, -50, -50, 19, + 76, -28, -29, 10, 11, 76, 20, 76, 76, -27, + -27, -27, 38, -25, 57, -21, 89, -22, -20, -23, + 83, 76, 76, 58, 76, 20, -50, -30, 13, 12, + -31, 14, -36, -39, -40, 58, 88, 61, -20, -18, + 93, 78, 79, 80, 81, 82, 66, -19, 71, 72, + 65, 76, -31, 76, 85, 22, 23, 5, 93, 93, + -37, 47, -55, -54, 76, -6, 44, 86, -45, 76, + 55, 93, 85, 61, 93, 76, 20, -31, -31, -36, + 87, 88, 90, 89, 74, 75, 63, -53, 67, 58, + -36, -36, 93, -36, 93, 93, 93, 76, 25, 24, + 25, 25, -12, -10, 76, -10, -49, 6, -36, -37, + 86, 75, -26, -27, 93, -19, 76, -20, 76, 89, + -23, 76, -8, -9, 76, 93, 76, -36, -36, -36, + -36, -36, -36, 65, 58, 59, 62, 77, -6, 94, + -36, -17, -16, -36, -10, -9, 76, 76, 76, 94, + 86, 94, -42, 50, 19, -49, -54, -36, -49, -28, + -6, 9, -45, -45, 94, 94, 86, 77, -10, 93, + 65, -36, 93, 94, 55, 94, 86, 94, 24, 35, + 76, 35, -43, 51, -36, 20, -42, -32, -33, -34, + -35, 73, -45, 94, 15, 26, -9, -44, 95, 93, + 94, -10, -6, -16, 77, -36, 76, -14, -15, 93, + -14, -36, -11, 76, 93, -43, -37, -33, 45, -45, + 76, 27, -52, 65, 58, 78, 78, 94, 94, 94, + 94, -56, 86, 20, -17, -10, -41, 48, -26, 94, + -11, -51, 64, 65, 96, 94, -15, 39, 94, 94, + -38, 46, 49, -49, -45, 94, 40, -47, 52, -36, + -13, -23, 20, 41, -42, 49, 86, -36, -43, -46, + -23, -23, 86, -48, 53, 54, -23, -48, } var yyDef = [...]int16{ 0, -2, 1, 4, 6, 7, 8, 10, 11, 12, - 0, 0, 0, 0, 0, 0, 0, 0, 75, 80, - 2, 5, 9, 27, 27, 27, 0, 14, 0, 97, - 0, 0, 0, 0, 0, 0, 0, 95, 78, 0, - 81, 3, 0, 0, 0, 0, 27, 15, 16, 100, - 0, 0, 18, 0, 0, 0, 0, 0, 112, 0, - 0, 79, 0, 82, 83, 131, 86, 0, 89, 13, - 0, 0, 0, 0, 96, 0, 0, 98, 0, 104, - -2, 135, 0, 0, 0, 142, 143, 0, 53, 54, - 55, 56, 57, 0, 59, 60, 61, 62, 89, 99, - 0, 0, 0, 0, 0, 40, 0, 124, 0, 112, - 37, 0, 76, 0, 0, 84, 132, 0, 0, 0, - 28, 0, 0, 0, 101, 102, 103, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 147, 136, 137, 0, - 0, 0, 49, 0, 22, 0, 0, 0, 0, 0, - 41, 45, 0, 118, 0, 113, 124, 0, 0, 124, - 97, 0, 131, 95, 131, 133, 0, 0, 90, 0, - 64, 0, 0, 0, 148, 149, 150, 151, 152, 153, - 154, 0, 0, 0, 145, 0, 144, 0, 0, 50, - 51, 0, 23, 24, 0, 26, 0, 0, 0, 120, - 0, 0, 118, 38, 39, -2, 131, 0, 0, 93, - 85, 87, 88, 0, 67, 0, 0, 155, 138, 0, - 139, 0, 63, 0, 21, 0, 0, 46, 0, 33, - 0, 119, 0, 120, 112, 106, -2, 0, 111, 91, - 131, 0, 0, 65, 72, 0, 0, 19, 0, 0, - 0, 0, 52, 25, 35, 42, 49, 32, 121, 125, - 29, 0, 34, 114, 108, 0, 92, 0, 0, 70, - 73, 0, 0, 0, 20, 140, 141, 58, 31, 0, - 0, 0, 0, 116, 0, 124, 131, 0, 66, 71, - 74, 68, 69, 43, 0, 44, 30, 122, 0, 0, - 0, 94, 17, 0, 118, 0, 117, 115, 47, 0, - 36, 120, 0, 0, 109, 77, 123, 128, 48, 0, - 126, 129, 130, 128, 127, + 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, + 82, 2, 5, 9, 27, 27, 27, 0, 14, 0, + 99, 0, 0, 0, 0, 0, 0, 0, 97, 80, + 77, 78, 0, 83, 3, 0, 0, 0, 0, 27, + 15, 16, 102, 0, 0, 18, 0, 0, 0, 0, + 0, 114, 0, 0, 81, 0, 84, 85, 133, 88, + 0, 91, 13, 0, 0, 0, 0, 98, 0, 0, + 100, 0, 106, -2, 137, 0, 0, 0, 144, 145, + 0, 53, 54, 55, 56, 57, 0, 59, 60, 61, + 62, 91, 101, 0, 0, 0, 0, 0, 40, 0, + 126, 0, 114, 37, 0, 76, 0, 0, 86, 134, + 0, 0, 0, 28, 0, 0, 0, 103, 104, 105, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, + 138, 139, 0, 0, 0, 49, 0, 22, 0, 0, + 0, 0, 0, 41, 45, 0, 120, 0, 115, 126, + 0, 0, 126, 99, 0, 133, 97, 133, 135, 0, + 0, 92, 0, 64, 0, 0, 0, 150, 151, 152, + 153, 154, 155, 156, 0, 0, 0, 147, 0, 146, + 0, 0, 50, 51, 0, 23, 24, 0, 26, 0, + 0, 0, 122, 0, 0, 120, 38, 39, -2, 133, + 0, 0, 95, 87, 89, 90, 0, 67, 0, 0, + 157, 140, 0, 141, 0, 63, 0, 21, 0, 0, + 46, 0, 33, 0, 121, 0, 122, 114, 108, -2, + 0, 113, 93, 133, 0, 0, 65, 72, 0, 0, + 19, 0, 0, 0, 0, 52, 25, 35, 42, 49, + 32, 123, 127, 29, 0, 34, 116, 110, 0, 94, + 0, 0, 70, 73, 0, 0, 0, 20, 142, 143, + 58, 31, 0, 0, 0, 0, 118, 0, 126, 133, + 0, 66, 71, 74, 68, 69, 43, 0, 44, 30, + 124, 0, 0, 0, 96, 17, 0, 120, 0, 119, + 117, 47, 0, 36, 122, 0, 0, 111, 79, 125, + 130, 48, 0, 128, 131, 132, 130, 129, } var yyTok1 = [...]int8{ @@ -462,12 +469,12 @@ var yyTok1 = [...]int8{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 90, 91, 86, 84, 83, 85, 88, 87, 3, 3, + 93, 94, 89, 87, 86, 88, 91, 90, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 92, 3, 93, + 3, 95, 3, 96, } var yyTok2 = [...]int8{ @@ -479,7 +486,7 @@ var yyTok2 = [...]int8{ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 89, + 82, 83, 84, 85, 92, } var yyTok3 = [...]int8{ @@ -1186,6 +1193,20 @@ yydefault: } } case 77: + yyDollar = yyS[yypt-2 : yypt+1] + { + yyVAL.stmt = &SelectStmt{ + ds: &FnDataSourceStmt{fnCall: &FnCall{fn: "databases"}}, + } + } + case 78: + yyDollar = yyS[yypt-2 : yypt+1] + { + yyVAL.stmt = &SelectStmt{ + ds: &FnDataSourceStmt{fnCall: &FnCall{fn: "tables"}}, + } + } + case 79: yyDollar = yyS[yypt-13 : yypt+1] { yyVAL.stmt = &SelectStmt{ @@ -1202,397 +1223,397 @@ yydefault: offset: yyDollar[13].exp, } } - case 78: + case 80: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.distinct = true } - case 79: + case 81: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.distinct = false } - case 80: + case 82: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.distinct = false } - case 81: + case 83: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.distinct = true } - case 82: + case 84: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.sels = nil } - case 83: + case 85: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.sels = yyDollar[1].sels } - case 84: + case 86: yyDollar = yyS[yypt-2 : yypt+1] { yyDollar[1].sel.setAlias(yyDollar[2].id) yyVAL.sels = []Selector{yyDollar[1].sel} } - case 85: + case 87: yyDollar = yyS[yypt-4 : yypt+1] { yyDollar[3].sel.setAlias(yyDollar[4].id) yyVAL.sels = append(yyDollar[1].sels, yyDollar[3].sel) } - case 86: + case 88: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.sel = yyDollar[1].col } - case 87: + case 89: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.sel = &AggColSelector{aggFn: yyDollar[1].aggFn, col: "*"} } - case 88: + case 90: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.sel = &AggColSelector{aggFn: yyDollar[1].aggFn, table: yyDollar[3].col.table, col: yyDollar[3].col.col} } - case 89: + case 91: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.col = &ColSelector{col: yyDollar[1].id} } - case 90: + case 92: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.col = &ColSelector{table: yyDollar[1].id, col: yyDollar[3].id} } - case 91: + case 93: yyDollar = yyS[yypt-3 : yypt+1] { yyDollar[1].tableRef.period = yyDollar[2].period yyDollar[1].tableRef.as = yyDollar[3].id yyVAL.ds = yyDollar[1].tableRef } - case 92: + case 94: yyDollar = yyS[yypt-4 : yypt+1] { yyDollar[2].stmt.(*SelectStmt).as = yyDollar[4].id yyVAL.ds = yyDollar[2].stmt.(DataSource) } - case 93: + case 95: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.ds = &FnDataSourceStmt{fnCall: yyDollar[1].value.(*FnCall), as: yyDollar[2].id} } - case 94: + case 96: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.ds = &tableRef{table: yyDollar[4].id, history: true, as: yyDollar[6].id} } - case 95: + case 97: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.tableRef = &tableRef{table: yyDollar[1].id} } - case 96: + case 98: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.period = period{start: yyDollar[1].openPeriod, end: yyDollar[2].openPeriod} } - case 97: + case 99: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.openPeriod = nil } - case 98: + case 100: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.openPeriod = &openPeriod{inclusive: true, instant: yyDollar[2].periodInstant} } - case 99: + case 101: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.openPeriod = &openPeriod{instant: yyDollar[2].periodInstant} } - case 100: + case 102: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.openPeriod = nil } - case 101: + case 103: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.openPeriod = &openPeriod{inclusive: true, instant: yyDollar[2].periodInstant} } - case 102: + case 104: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.openPeriod = &openPeriod{instant: yyDollar[2].periodInstant} } - case 103: + case 105: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.periodInstant = periodInstant{instantType: txInstant, exp: yyDollar[2].exp} } - case 104: + case 106: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.periodInstant = periodInstant{instantType: timeInstant, exp: yyDollar[1].exp} } - case 105: + case 107: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.joins = nil } - case 106: + case 108: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.joins = yyDollar[1].joins } - case 107: + case 109: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.joins = []*JoinSpec{yyDollar[1].join} } - case 108: + case 110: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.joins = append([]*JoinSpec{yyDollar[1].join}, yyDollar[2].joins...) } - case 109: + case 111: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.join = &JoinSpec{joinType: yyDollar[1].joinType, ds: yyDollar[3].ds, indexOn: yyDollar[4].ids, cond: yyDollar[6].exp} } - case 110: + case 112: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.joinType = InnerJoin } - case 111: + case 113: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.joinType = yyDollar[1].joinType } - case 112: + case 114: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 113: + case 115: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 114: + case 116: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.cols = nil } - case 115: + case 117: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.cols = yyDollar[3].cols } - case 116: + case 118: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 117: + case 119: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 118: + case 120: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 119: + case 121: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 120: + case 122: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 121: + case 123: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 122: + case 124: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.ordcols = nil } - case 123: + case 125: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.ordcols = yyDollar[3].ordcols } - case 124: + case 126: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.ids = nil } - case 125: + case 127: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.ids = yyDollar[4].ids } - case 126: + case 128: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.ordcols = []*OrdCol{{sel: yyDollar[1].col, descOrder: yyDollar[2].opt_ord}} } - case 127: + case 129: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.ordcols = append(yyDollar[1].ordcols, &OrdCol{sel: yyDollar[3].col, descOrder: yyDollar[4].opt_ord}) } - case 128: + case 130: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.opt_ord = false } - case 129: + case 131: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.opt_ord = false } - case 130: + case 132: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.opt_ord = true } - case 131: + case 133: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.id = "" } - case 132: + case 134: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.id = yyDollar[1].id } - case 133: + case 135: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.id = yyDollar[2].id } - case 134: + case 136: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].exp } - case 135: + case 137: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].binExp } - case 136: + case 138: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = &NotBoolExp{exp: yyDollar[2].exp} } - case 137: + case 139: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = &NumExp{left: &Integer{val: 0}, op: SUBSOP, right: yyDollar[2].exp} } - case 138: + case 140: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.exp = &LikeBoolExp{val: yyDollar[1].exp, notLike: yyDollar[2].boolean, pattern: yyDollar[4].exp} } - case 139: + case 141: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.exp = &ExistsBoolExp{q: (yyDollar[3].stmt).(DataSource)} } - case 140: + case 142: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.exp = &InSubQueryExp{val: yyDollar[1].exp, notIn: yyDollar[2].boolean, q: yyDollar[5].stmt.(*SelectStmt)} } - case 141: + case 143: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.exp = &InListExp{val: yyDollar[1].exp, notIn: yyDollar[2].boolean, values: yyDollar[5].values} } - case 142: + case 144: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].sel } - case 143: + case 145: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].value } - case 144: + case 146: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 145: + case 147: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.exp = &Cast{val: yyDollar[1].exp, t: yyDollar[3].sqlType} } - case 146: + case 148: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.boolean = false } - case 147: + case 149: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.boolean = true } - case 148: + case 150: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: ADDOP, right: yyDollar[3].exp} } - case 149: + case 151: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: SUBSOP, right: yyDollar[3].exp} } - case 150: + case 152: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: DIVOP, right: yyDollar[3].exp} } - case 151: + case 153: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: MULTOP, right: yyDollar[3].exp} } - case 152: + case 154: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &BinBoolExp{left: yyDollar[1].exp, op: yyDollar[2].logicOp, right: yyDollar[3].exp} } - case 153: + case 155: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: yyDollar[2].cmpOp, right: yyDollar[3].exp} } - case 154: + case 156: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: EQ, right: &NullValue{t: AnyType}} } - case 155: + case 157: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: NE, right: &NullValue{t: AnyType}} From 8f4e1db0db963c8546b776e87f10db9e9d48b8b7 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 27 Oct 2023 15:05:40 +0200 Subject: [PATCH 14/23] chore(pkg/server): set dynamic immudb server port in pgsql server Signed-off-by: Jeronimo Irazabal --- pkg/server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/server/server.go b/pkg/server/server.go index cd1676a64a..b924cdbeb6 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -253,7 +253,7 @@ func (s *ImmuServer) Initialize() error { s.PgsqlSrv = pgsqlsrv.New( pgsqlsrv.Host(s.Options.Address), pgsqlsrv.Port(s.Options.PgsqlServerPort), - pgsqlsrv.ImmudbPort(s.Options.Port), + pgsqlsrv.ImmudbPort(s.Listener.Addr().(*net.TCPAddr).Port), pgsqlsrv.TLSConfig(s.Options.TLSConfig), pgsqlsrv.Logger(s.Logger), pgsqlsrv.DatabaseList(s.dbList), From 8ef4251aa12aebc29c295eec3302e5aaa29b5562 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 27 Oct 2023 15:06:54 +0200 Subject: [PATCH 15/23] chore(pkg/pgsql): protocol enhancements Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/errors/errors.go | 2 +- pkg/pgsql/server/initialize_session.go | 46 ++++++++++---------- pkg/pgsql/server/query_machine.go | 58 +++++++++++++------------- 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/pkg/pgsql/errors/errors.go b/pkg/pgsql/errors/errors.go index 040026be47..3f790cf9e7 100644 --- a/pkg/pgsql/errors/errors.go +++ b/pkg/pgsql/errors/errors.go @@ -29,7 +29,7 @@ var ErrDBNotprovided = errors.New("database name not provided") var ErrUsernameNotprovided = errors.New("user name not provided") var ErrPwNotprovided = errors.New("password not provided") var ErrDBNotExists = errors.New("selected db doesn't exists") -var ErrUsernameNotFound = errors.New("user not found") +var ErrInvalidUsernameOrPassword = errors.New("invalid user name or password") var ErrExpectedQueryMessage = errors.New("expected query message") var ErrUseDBStatementNotSupported = errors.New("SQL statement not supported") var ErrSSLNotSupported = errors.New("SSL not supported") diff --git a/pkg/pgsql/server/initialize_session.go b/pkg/pgsql/server/initialize_session.go index 205e6b971f..48ccacb061 100644 --- a/pkg/pgsql/server/initialize_session.go +++ b/pkg/pgsql/server/initialize_session.go @@ -161,32 +161,31 @@ func (s *session) HandleStartup(ctx context.Context) (err error) { return err } - if pw, ok := msg.(fm.PasswordMsg); ok { - if !ok || pw.GetSecret() == "" { - return pserr.ErrPwNotprovided - } + pw, ok := msg.(fm.PasswordMsg) + if !ok || pw.GetSecret() == "" { + return pserr.ErrPwNotprovided + } - opts := client.DefaultOptions(). - WithAddress(s.immudbHost). - WithPort(s.immudbPort). - WithDisableIdentityCheck(true) + opts := client.DefaultOptions(). + WithAddress(s.immudbHost). + WithPort(s.immudbPort). + WithDisableIdentityCheck(true) - s.client = client.NewClient().WithOptions(opts) + s.client = client.NewClient().WithOptions(opts) - err := s.client.OpenSession(ctx, []byte(user), []byte(pw.GetSecret()), db) - if err != nil { - return err - } + err = s.client.OpenSession(ctx, []byte(user), []byte(pw.GetSecret()), db) + if err != nil { + return err + } - s.client.CurrentState(context.Background()) + s.client.CurrentState(context.Background()) - sessionID := s.client.GetSessionID() - s.ctx = metadata.NewIncomingContext(context.Background(), metadata.Pairs("sessionid", sessionID)) + sessionID := s.client.GetSessionID() + s.ctx = metadata.NewIncomingContext(context.Background(), metadata.Pairs("sessionid", sessionID)) - s.log.Debugf("authentication successful for %s", user) - if _, err := s.writeMessage(bm.AuthenticationOk()); err != nil { - return err - } + s.log.Debugf("authentication successful for %s", user) + if _, err := s.writeMessage(bm.AuthenticationOk()); err != nil { + return err } if _, err := s.writeMessage(bm.ParameterStatus([]byte("standard_conforming_strings"), []byte("on"))); err != nil { @@ -213,5 +212,10 @@ func parseProtocolVersion(payload []byte) string { func (s *session) Close() error { s.mr.CloseConnection() - return s.client.CloseSession(s.ctx) + + if s.client != nil { + return s.client.CloseSession(s.ctx) + } + + return nil } diff --git a/pkg/pgsql/server/query_machine.go b/pkg/pgsql/server/query_machine.go index ea6238f14e..9d4c1cb37e 100644 --- a/pkg/pgsql/server/query_machine.go +++ b/pkg/pgsql/server/query_machine.go @@ -86,40 +86,34 @@ func (s *session) QueryMachine() error { var resCols []*schema.Column var stmt sql.SQLStmt - if s.isInBlackList(v.Statements) { - _, err := s.writeMessage(bm.ParseComplete()) + if !s.isInBlackList(v.Statements) { + stmts, err := sql.Parse(strings.NewReader(v.Statements)) if err != nil { waitForSync = extQueryMode + s.HandleError(err) + continue } - continue - } - stmts, err := sql.Parse(strings.NewReader(v.Statements)) - if err != nil { - waitForSync = extQueryMode - s.HandleError(err) - continue - } - - // Note: as stated in the pgsql spec, the query string contained in a Parse message cannot include more than one SQL statement; - // else a syntax error is reported. This restriction does not exist in the simple-query protocol, but it does exist - // in the extended protocol, because allowing prepared statements or portals to contain multiple commands would - // complicate the protocol unduly. - if len(stmts) > 1 { - waitForSync = extQueryMode - s.HandleError(pserr.ErrMaxStmtNumberExceeded) - continue - } - if len(stmts) == 0 { - waitForSync = extQueryMode - s.HandleError(pserr.ErrNoStatementFound) - continue - } + // Note: as stated in the pgsql spec, the query string contained in a Parse message cannot include more than one SQL statement; + // else a syntax error is reported. This restriction does not exist in the simple-query protocol, but it does exist + // in the extended protocol, because allowing prepared statements or portals to contain multiple commands would + // complicate the protocol unduly. + if len(stmts) > 1 { + waitForSync = extQueryMode + s.HandleError(pserr.ErrMaxStmtNumberExceeded) + continue + } + if len(stmts) == 0 { + waitForSync = extQueryMode + s.HandleError(pserr.ErrNoStatementFound) + continue + } - if paramCols, resCols, err = s.inferParamAndResultCols(stmts[0]); err != nil { - waitForSync = extQueryMode - s.HandleError(err) - continue + if paramCols, resCols, err = s.inferParamAndResultCols(stmts[0]); err != nil { + waitForSync = extQueryMode + s.HandleError(err) + continue + } } _, err = s.writeMessage(bm.ParseComplete()) @@ -258,13 +252,17 @@ func (s *session) fetchAndWriteResults(statements string, parameters []*schema.N } if s.isInBlackList(statements) { - return nil + _, err := s.writeMessage(bm.CommandComplete([]byte("ok"))) + return err } if i := s.isEmulableInternally(statements); i != nil { if err := s.tryToHandleInternally(i); err != nil && err != pserr.ErrMessageCannotBeHandledInternally { return err } + + _, err := s.writeMessage(bm.CommandComplete([]byte("ok"))) + return err } stmts, err := sql.Parse(strings.NewReader(statements)) From e724e98547be7e8009a16680c3cc4fcb7d7d703b Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 27 Oct 2023 15:07:27 +0200 Subject: [PATCH 16/23] test(pkg/pgsql): integration tests Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/pgsql_integration_test.go | 832 +++++++++++++++------ pkg/pgsql/server/query_machine_test.go | 2 +- 2 files changed, 606 insertions(+), 228 deletions(-) diff --git a/pkg/pgsql/server/pgsql_integration_test.go b/pkg/pgsql/server/pgsql_integration_test.go index 553e024fb4..a48bf9aadc 100644 --- a/pkg/pgsql/server/pgsql_integration_test.go +++ b/pkg/pgsql/server/pgsql_integration_test.go @@ -24,7 +24,6 @@ import ( "fmt" "math/rand" "os" - "sync" "testing" "time" @@ -32,26 +31,41 @@ import ( "github.com/codenotary/immudb/pkg/pgsql/errors" "github.com/codenotary/immudb/pkg/pgsql/server/pgmeta" "github.com/codenotary/immudb/pkg/server" - "github.com/codenotary/immudb/pkg/server/servertest" "github.com/jackc/pgx/v4" - "github.com/lib/pq" - _ "github.com/lib/pq" + pq "github.com/lib/pq" + "github.com/stretchr/testify/require" ) func TestPgsqlServer_SimpleQuery(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - bs.WaitForPgsqlListener() + defer func() { + srv.Stop() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -71,17 +85,33 @@ func TestPgsqlServer_SimpleQuery(t *testing.T) { func TestPgsqlServer_SimpleQueryBlob(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - bs.WaitForPgsqlListener() + defer func() { + srv.Stop() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -107,17 +137,33 @@ func TestPgsqlServer_SimpleQueryBlob(t *testing.T) { func TestPgsqlServer_SimpleQueryBool(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - bs.WaitForPgsqlListener() + defer func() { + srv.Stop() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -138,17 +184,33 @@ func TestPgsqlServer_SimpleQueryBool(t *testing.T) { func TestPgsqlServer_SimpleQueryExecError(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } - bs.WaitForPgsqlListener() + go func() { + srv.Start() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) _, err = db.Exec("ILLEGAL STATEMENT") @@ -157,17 +219,33 @@ func TestPgsqlServer_SimpleQueryExecError(t *testing.T) { func TestPgsqlServer_SimpleQueryQueryError(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } - bs.WaitForPgsqlListener() + go func() { + srv.Start() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) err = db.QueryRow("SELECT id, amount, title, isPresent FROM notExists").Scan() @@ -176,17 +254,33 @@ func TestPgsqlServer_SimpleQueryQueryError(t *testing.T) { func TestPgsqlServer_SimpleQueryQueryMissingDatabase(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() - bs.WaitForPgsqlListener() + defer os.Remove(".state-") - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) err = db.QueryRow("SELECT id, amount, title, isPresent FROM notExists").Scan() @@ -195,17 +289,33 @@ func TestPgsqlServer_SimpleQueryQueryMissingDatabase(t *testing.T) { func TestPgsqlServer_SimpleQueryQueryDatabaseNotExists(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - bs.WaitForPgsqlListener() + err := srv.Initialize() + if err != nil { + panic(err) + } - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=notexists password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=notexists password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) err = db.QueryRow("SELECT id, amount, title, isPresent FROM notExists").Scan() @@ -214,36 +324,68 @@ func TestPgsqlServer_SimpleQueryQueryDatabaseNotExists(t *testing.T) { func TestPgsqlServer_SimpleQueryQueryMissingUsername(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - bs.WaitForPgsqlListener() + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) err = db.QueryRow("SELECT id, amount, title, isPresent FROM notExists").Scan() - require.ErrorContains(t, err, errors.ErrUsernameNotFound.Error()) + require.ErrorContains(t, err, errors.ErrInvalidUsernameOrPassword.Error()) } func TestPgsqlServer_SimpleQueryQueryMissingPassword(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - bs.WaitForPgsqlListener() + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb", bs.Server.Srv.PgsqlSrv.GetPort())) + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) err = db.QueryRow("SELECT id, amount, title, isPresent FROM notExists").Scan() @@ -252,18 +394,34 @@ func TestPgsqlServer_SimpleQueryQueryMissingPassword(t *testing.T) { func TestPgsqlServer_SimpleQueryQueryClosedConnError(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } - bs.WaitForPgsqlListener() + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb", bs.Server.Srv.PgsqlSrv.GetPort())) + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) - bs.Stop() err = db.QueryRow("SELECT id, amount, title, isPresent FROM notExists").Scan() require.Error(t, err) @@ -271,17 +429,33 @@ func TestPgsqlServer_SimpleQueryQueryClosedConnError(t *testing.T) { func TestPgsqlServer_SimpleQueryTerminate(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() - bs.WaitForPgsqlListener() + defer os.Remove(".state-") - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -304,17 +478,33 @@ func TestPgsqlServer_SimpleQueryTerminate(t *testing.T) { func TestPgsqlServer_SimpleQueryQueryEmptyQueryMessage(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - bs.WaitForPgsqlListener() + defer func() { + srv.Stop() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -334,21 +524,38 @@ func TestPgsqlServer_SimpleQueryQueryEmptyQueryMessage(t *testing.T) { func TestPgsqlServer_SimpleQueryQueryCreateOrUseDatabaseNotSupported(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - bs.WaitForPgsqlListener() + defer func() { + srv.Stop() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) _, err = db.Exec("CREATE DATABASE db") - require.Error(t, err) + require.NoError(t, err) + _, err = db.Exec("USE DATABASE db") require.ErrorContains(t, err, errors.ErrUseDBStatementNotSupported.Error()) @@ -356,17 +563,33 @@ func TestPgsqlServer_SimpleQueryQueryCreateOrUseDatabaseNotSupported(t *testing. func TestPgsqlServer_SimpleQueryQueryExecError(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - bs.WaitForPgsqlListener() + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -392,6 +615,7 @@ NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc 6MF9+Yw1Yy0t -----END CERTIFICATE-----`) + keyPem := []byte(`-----BEGIN EC PRIVATE KEY----- MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49 AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q @@ -400,39 +624,73 @@ EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA== cert, err := tls.X509KeyPair(certPem, keyPem) require.NoError(t, err) + cfg := &tls.Config{Certificates: []tls.Certificate{cert}} - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0).WithTLS(cfg) - bs := servertest.NewBufconnServer(options) + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false). + WithTLS(cfg) - bs.Start() - defer bs.Stop() + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - defer os.Remove(".state-") + err = srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - bs.WaitForPgsqlListener() + defer func() { + srv.Stop() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=require user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=require user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() + _, err = db.Exec(fmt.Sprintf("CREATE TABLE %s (id INTEGER, amount INTEGER, title VARCHAR, content BLOB, PRIMARY KEY id)", table)) require.NoError(t, err) } func TestPgsqlServer_SSLNotEnabled(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } - bs.WaitForPgsqlListener() + go func() { + srv.Start() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=require user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=require user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -441,59 +699,35 @@ func TestPgsqlServer_SSLNotEnabled(t *testing.T) { } -func _TestPgsqlServer_SimpleQueryAsynch(t *testing.T) { +func TestPgsqlServer_VersionStatement(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - - bs.Start() - defer bs.Stop() - - defer os.Remove(".state-") - - bs.WaitForPgsqlListener() - - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) - require.NoError(t, err) - - table := getRandomTableName() - result, err := db.Exec(fmt.Sprintf("CREATE TABLE %s (id INTEGER, amount INTEGER, title VARCHAR, content BLOB, PRIMARY KEY id)", table)) - require.NoError(t, err) - require.NotNil(t, result) - _, err = db.Exec(fmt.Sprintf("UPSERT INTO %s (id, amount, title) VALUES (1, 200, 'title 1')", table)) - require.NoError(t, err) + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - var wg sync.WaitGroup - for i := 0; i < 10; i++ { - wg.Add(1) - go func(c int) { - defer wg.Done() - var title string - var id int64 - var amount int64 - err = db.QueryRow(fmt.Sprintf("SELECT id, amount, title FROM %s", table)).Scan(&id, &amount, &title) - require.NoError(t, err) + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - }(i) + err := srv.Initialize() + if err != nil { + panic(err) } - wg.Wait() -} + go func() { + srv.Start() + }() -func TestPgsqlServer_VersionStatement(t *testing.T) { - td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - - bs.Start() - defer bs.Stop() + defer func() { + srv.Stop() + }() defer os.Remove(".state-") - bs.WaitForPgsqlListener() - - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) var version string @@ -504,17 +738,33 @@ func TestPgsqlServer_VersionStatement(t *testing.T) { func TestPgsqlServerSetStatement(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } - bs.WaitForPgsqlListener() + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) _, err = db.Query("SET test=val") @@ -523,17 +773,33 @@ func TestPgsqlServerSetStatement(t *testing.T) { func TestPgsqlServer_SimpleQueryNilValues(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } - bs.WaitForPgsqlListener() + go func() { + srv.Start() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -561,17 +827,33 @@ func getRandomTableName() string { func TestPgsqlServer_ExtendedQueryPG(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - bs.WaitForPgsqlListener() + defer func() { + srv.Stop() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -591,17 +873,33 @@ func TestPgsqlServer_ExtendedQueryPG(t *testing.T) { func TestPgsqlServer_ExtendedQueryPGxNamedStatements(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - bs.WaitForPgsqlListener() + defer func() { + srv.Stop() + }() - db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer os.Remove(".state-") + + db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) //db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=5432 sslmode=disable user=postgres dbname=postgres password=postgres")) require.NoError(t, err) @@ -624,17 +922,33 @@ func TestPgsqlServer_ExtendedQueryPGxNamedStatements(t *testing.T) { func TestPgsqlServer_ExtendedQueryPGxMultiFieldsPreparedStatements(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - bs.WaitForPgsqlListener() + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() - db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) defer db.Close(context.Background()) @@ -667,17 +981,33 @@ func TestPgsqlServer_ExtendedQueryPGxMultiFieldsPreparedStatements(t *testing.T) func TestPgsqlServer_ExtendedQueryPGMultiFieldsPreparedStatements(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } - bs.WaitForPgsqlListener() + go func() { + srv.Start() + }() - db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := sql.Open("postgres", fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -708,17 +1038,33 @@ func TestPgsqlServer_ExtendedQueryPGMultiFieldsPreparedStatements(t *testing.T) func TestPgsqlServer_ExtendedQueryPGMultiFieldsPreparedInsert(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) + + err := srv.Initialize() + if err != nil { + panic(err) + } - bs.WaitForPgsqlListener() + go func() { + srv.Start() + }() - db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -727,10 +1073,10 @@ func TestPgsqlServer_ExtendedQueryPGMultiFieldsPreparedInsert(t *testing.T) { require.NotNil(t, result) binaryContent := []byte("my blob content1") blobContent := hex.EncodeToString(binaryContent) - _, err = db.Exec(context.Background(), fmt.Sprintf("INSERT INTO %s (id, amount, total, title, content, isPresent) VALUES (?, ?, ?, ?, ?, ?)", table), 1, 1000, 6000, "title 1", fmt.Sprintf("%s", blobContent), true) + _, err = db.Exec(context.Background(), fmt.Sprintf("INSERT INTO %s (id, amount, total, title, content, isPresent) VALUES (?, ?, ?, ?, ?, ?)", table), 1, 1000, 6000, "title 1", blobContent, true) require.NoError(t, err) blobContent2 := hex.EncodeToString([]byte("my blob content2")) - _, err = db.Exec(context.Background(), fmt.Sprintf("INSERT INTO %s (id, amount, total, title, content, isPresent) VALUES (?, ?, ?, ?, ?, ?)", table), 2, 2000, 12000, "title 2", fmt.Sprintf("%s", blobContent2), true) + _, err = db.Exec(context.Background(), fmt.Sprintf("INSERT INTO %s (id, amount, total, title, content, isPresent) VALUES (?, ?, ?, ?, ?, ?)", table), 2, 2000, 12000, "title 2", blobContent2, true) require.NoError(t, err) var id int64 @@ -749,17 +1095,33 @@ func TestPgsqlServer_ExtendedQueryPGMultiFieldsPreparedInsert(t *testing.T) { func TestPgsqlServer_ExtendedQueryPGxMultiInsertStatements(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - bs.WaitForPgsqlListener() + err := srv.Initialize() + if err != nil { + panic(err) + } - db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") + + db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) //db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=5432 sslmode=disable user=postgres dbname=postgres password=postgres")) require.NoError(t, err) @@ -782,17 +1144,33 @@ func TestPgsqlServer_ExtendedQueryPGxMultiInsertStatements(t *testing.T) { func TestPgsqlServer_ExtendedQueryPGMultiFieldsPreparedMultiInsertError(t *testing.T) { td := t.TempDir() - options := server.DefaultOptions().WithDir(td).WithPgsqlServer(true).WithPgsqlServerPort(0) - bs := servertest.NewBufconnServer(options) - bs.Start() - defer bs.Stop() + options := server.DefaultOptions(). + WithDir(td). + WithPort(0). + WithPgsqlServer(true). + WithPgsqlServerPort(0). + WithMetricsServer(false). + WithWebServer(false) - defer os.Remove(".state-") + srv := server.DefaultServer().WithOptions(options).(*server.ImmuServer) - bs.WaitForPgsqlListener() + err := srv.Initialize() + if err != nil { + panic(err) + } + + go func() { + srv.Start() + }() + + defer func() { + srv.Stop() + }() + + defer os.Remove(".state-") - db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", bs.Server.Srv.PgsqlSrv.GetPort())) + db, err := pgx.Connect(context.Background(), fmt.Sprintf("host=localhost port=%d sslmode=disable user=immudb dbname=defaultdb password=immudb", srv.PgsqlSrv.GetPort())) require.NoError(t, err) table := getRandomTableName() @@ -802,6 +1180,6 @@ func TestPgsqlServer_ExtendedQueryPGMultiFieldsPreparedMultiInsertError(t *testi binaryContent := []byte("my blob content1") blobContent2 := hex.EncodeToString([]byte("my blob content2")) blobContent := hex.EncodeToString(binaryContent) - _, err = db.Exec(context.Background(), fmt.Sprintf("INSERT INTO %s (id, amount, total, title, content, isPresent) VALUES (?, ?, ?, ?, ?, ?); INSERT INTO %s (id, amount, total, title, content, isPresent) VALUES (?, ?, ?, ?, ?, ?)", table, table), 1, 1000, 6000, "title 1", fmt.Sprintf("%s", blobContent), true, 2, 2000, 12000, "title 2", fmt.Sprintf("%s", blobContent2), true) + _, err = db.Exec(context.Background(), fmt.Sprintf("INSERT INTO %s (id, amount, total, title, content, isPresent) VALUES (?, ?, ?, ?, ?, ?); INSERT INTO %s (id, amount, total, title, content, isPresent) VALUES (?, ?, ?, ?, ?, ?)", table, table), 1, 1000, 6000, "title 1", blobContent, true, 2, 2000, 12000, "title 2", blobContent2, true) require.ErrorContains(t, err, errors.ErrMaxStmtNumberExceeded.Error()) } diff --git a/pkg/pgsql/server/query_machine_test.go b/pkg/pgsql/server/query_machine_test.go index 7d6d78925c..15585063c8 100644 --- a/pkg/pgsql/server/query_machine_test.go +++ b/pkg/pgsql/server/query_machine_test.go @@ -321,7 +321,7 @@ func TestSession_QueriesMachine(t *testing.T) { }, out: nil, portals: map[string]*portal{ - "port": &portal{ + "port": { Statement: &statement{ SQLStatement: "test", }, From 4ddfa7b7f7bb5655bb8dc1b872b22bdc7dc69eaa Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 27 Oct 2023 15:16:04 +0200 Subject: [PATCH 17/23] chore(embedded/sql): continue to support databases and tables datasources Signed-off-by: Jeronimo Irazabal --- embedded/sql/sql_grammar.y | 10 + embedded/sql/sql_parser.go | 433 +++++++++++++++++++------------------ 2 files changed, 233 insertions(+), 210 deletions(-) diff --git a/embedded/sql/sql_grammar.y b/embedded/sql/sql_grammar.y index 63b8badca5..c065476f0e 100644 --- a/embedded/sql/sql_grammar.y +++ b/embedded/sql/sql_grammar.y @@ -640,6 +640,16 @@ ds: $2.(*SelectStmt).as = $4 $$ = $2.(DataSource) } +| + DATABASES '(' ')' opt_as + { + $$ = &FnDataSourceStmt{fnCall: &FnCall{fn: "databases"}, as: $4} + } +| + TABLES '(' ')' opt_as + { + $$ = &FnDataSourceStmt{fnCall: &FnCall{fn: "tables"}, as: $4} + } | fnCall opt_as { diff --git a/embedded/sql/sql_parser.go b/embedded/sql/sql_parser.go index c5ec1dc80f..fae40084ee 100644 --- a/embedded/sql/sql_parser.go +++ b/embedded/sql/sql_parser.go @@ -249,109 +249,110 @@ var yyExca = [...]int16{ 1, -1, -2, 0, -1, 83, - 59, 148, - 62, 148, - -2, 136, - -1, 208, - 45, 112, - -2, 107, - -1, 239, - 45, 112, + 59, 150, + 62, 150, + -2, 138, + -1, 210, + 45, 114, -2, 109, + -1, 243, + 45, 114, + -2, 111, } const yyPrivate = 57344 -const yyLast = 411 +const yyLast = 419 var yyAct = [...]int16{ - 82, 323, 69, 202, 118, 232, 156, 258, 262, 97, - 162, 153, 191, 238, 110, 257, 6, 192, 173, 51, - 88, 113, 294, 249, 200, 248, 226, 200, 20, 305, - 200, 200, 299, 200, 279, 277, 298, 81, 250, 227, - 295, 201, 263, 289, 85, 280, 278, 87, 243, 225, - 223, 100, 96, 166, 19, 215, 214, 98, 99, 264, - 22, 199, 101, 68, 91, 92, 93, 94, 95, 70, - 164, 259, 222, 219, 86, 145, 175, 122, 146, 90, + 82, 331, 69, 204, 118, 236, 156, 264, 268, 97, + 162, 153, 193, 242, 110, 263, 6, 194, 175, 51, + 88, 113, 302, 313, 165, 166, 202, 255, 20, 254, + 230, 168, 202, 202, 307, 202, 306, 81, 287, 303, + 285, 256, 202, 231, 85, 297, 288, 87, 164, 22, + 203, 100, 96, 269, 19, 286, 250, 98, 99, 249, + 247, 229, 101, 68, 91, 92, 93, 94, 95, 70, + 270, 284, 227, 219, 86, 218, 201, 122, 265, 90, 115, 85, 129, 136, 87, 145, 140, 141, 100, 96, - 144, 143, 142, 124, 98, 99, 121, 109, 108, 101, - 322, 91, 92, 93, 94, 95, 70, 130, 131, 133, - 132, 86, 158, 136, 283, 316, 90, 136, 282, 226, - 216, 155, 111, 200, 170, 136, 165, 159, 134, 135, - 117, 177, 178, 179, 180, 181, 182, 135, 167, 133, - 132, 130, 131, 133, 132, 190, 193, 71, 189, 130, - 131, 133, 132, 122, 70, 71, 71, 104, 194, 188, - 66, 160, 207, 70, 276, 275, 205, 195, 169, 208, - 212, 85, 213, 254, 87, 80, 245, 217, 100, 96, - 282, 210, 206, 209, 98, 99, 221, 218, 187, 101, - 120, 91, 92, 93, 94, 95, 70, 29, 30, 71, - 154, 86, 270, 256, 234, 56, 90, 230, 114, 236, - 198, 119, 197, 196, 242, 174, 176, 171, 168, 147, - 125, 103, 74, 193, 224, 72, 174, 255, 38, 58, - 102, 251, 136, 55, 261, 246, 50, 161, 136, 252, - 253, 241, 265, 134, 135, 40, 41, 260, 269, 134, - 135, 211, 266, 267, 127, 128, 130, 131, 133, 132, - 193, 57, 130, 131, 133, 132, 28, 20, 139, 293, - 220, 292, 284, 123, 274, 184, 285, 138, 165, 288, - 290, 273, 183, 136, 20, 185, 73, 46, 186, 64, - 296, 39, 308, 19, 304, 303, 324, 325, 233, 203, - 45, 315, 309, 302, 287, 311, 10, 12, 11, 111, - 19, 314, 301, 317, 268, 116, 36, 43, 320, 321, - 318, 313, 306, 13, 163, 326, 47, 48, 327, 297, - 7, 62, 8, 9, 14, 15, 231, 35, 16, 17, - 229, 34, 37, 23, 20, 271, 149, 150, 151, 148, - 76, 107, 228, 2, 24, 312, 235, 126, 75, 59, - 60, 61, 204, 49, 25, 27, 26, 33, 105, 106, - 19, 31, 244, 32, 79, 78, 44, 53, 54, 157, - 21, 281, 112, 137, 272, 291, 307, 319, 247, 286, - 84, 83, 300, 240, 239, 237, 77, 52, 63, 42, - 67, 65, 89, 310, 152, 172, 18, 5, 4, 3, - 1, + 226, 143, 223, 145, 98, 99, 215, 214, 177, 101, + 146, 91, 92, 93, 94, 95, 70, 130, 131, 133, + 132, 86, 158, 136, 144, 142, 90, 136, 124, 121, + 109, 155, 108, 330, 172, 136, 167, 159, 134, 135, + 291, 179, 180, 181, 182, 183, 184, 135, 169, 133, + 132, 130, 131, 133, 132, 192, 195, 71, 191, 130, + 131, 133, 132, 111, 70, 71, 324, 122, 196, 190, + 66, 290, 209, 230, 220, 104, 207, 197, 171, 210, + 202, 117, 216, 283, 217, 260, 251, 85, 221, 71, + 87, 212, 208, 211, 100, 96, 70, 71, 225, 222, + 98, 99, 160, 136, 80, 101, 290, 91, 92, 93, + 94, 95, 70, 120, 134, 135, 238, 86, 29, 30, + 189, 240, 90, 56, 154, 276, 246, 130, 131, 133, + 132, 262, 234, 114, 119, 200, 176, 195, 228, 199, + 198, 261, 176, 178, 173, 257, 136, 170, 267, 252, + 147, 125, 103, 258, 259, 74, 271, 134, 135, 102, + 72, 266, 275, 38, 277, 278, 272, 273, 58, 55, + 130, 131, 133, 132, 50, 161, 195, 245, 20, 57, + 139, 40, 41, 127, 128, 213, 282, 28, 292, 138, + 186, 301, 293, 281, 167, 296, 224, 185, 298, 300, + 136, 123, 187, 73, 19, 188, 46, 64, 304, 39, + 332, 333, 312, 311, 316, 237, 205, 323, 20, 310, + 317, 295, 111, 319, 10, 12, 11, 309, 45, 322, + 274, 325, 116, 36, 43, 321, 328, 329, 326, 314, + 163, 13, 305, 334, 19, 62, 335, 235, 7, 233, + 8, 9, 14, 15, 47, 48, 16, 17, 37, 35, + 34, 23, 20, 279, 149, 150, 151, 148, 107, 232, + 2, 24, 320, 239, 126, 59, 60, 61, 76, 75, + 206, 25, 27, 26, 49, 105, 106, 31, 19, 32, + 33, 248, 21, 44, 79, 78, 53, 54, 157, 289, + 112, 137, 280, 299, 315, 327, 253, 294, 84, 83, + 308, 244, 243, 241, 77, 52, 63, 42, 67, 65, + 89, 318, 152, 174, 18, 5, 4, 3, 1, } var yyPact = [...]int16{ - 302, -1000, -1000, -32, -1000, -1000, -1000, 314, -1000, -1000, - 347, 190, 354, 350, 307, 303, 272, 152, 235, 176, - 274, -1000, 302, -1000, 227, 227, 227, 344, -1000, 160, - 367, 157, 185, 153, 152, 152, 152, 293, -1000, 232, - -1000, -1000, 71, -1000, -1000, 149, 228, 146, 338, 227, - -1000, -1000, 362, 23, 23, -1000, 145, 72, 346, 5, - 4, 262, 132, 225, -1000, 271, -1000, 44, 135, -1000, - 3, 68, -1000, 212, 0, 144, 337, -1000, 23, 23, - -1000, 113, 175, 210, -1000, 113, 113, -1, -1000, -1000, - 113, -1000, -1000, -1000, -1000, -1000, -3, -1000, -1000, -1000, - -1000, -8, -1000, -15, 143, 324, 322, 323, 124, 124, - 373, 113, 75, -1000, 162, -1000, -23, 80, -1000, -1000, - 142, 79, 141, -1000, 139, -17, 140, -1000, -1000, 175, - 113, 113, 113, 113, 113, 113, 217, 226, 111, -1000, - 62, 50, 225, 54, 113, 113, 124, -1000, 139, 137, - 136, 134, -33, 37, -1000, -53, 249, 343, 175, 373, - 132, 113, 373, 367, 242, 135, -18, 135, -1000, -38, - -39, -1000, 34, -1000, 100, 124, -20, 50, 50, 220, - 220, 62, 20, -1000, 205, 113, -21, -1000, -44, -1000, - 169, -45, 33, 175, -55, -1000, -1000, 328, -1000, 305, - 131, 301, 247, 113, 336, 249, -1000, 175, 168, 135, - -46, 357, -1000, -1000, -1000, -1000, 150, -70, -56, 124, - -1000, 62, -14, -1000, 96, -1000, 113, -1000, 127, -22, - -1000, -22, -1000, 113, 175, -34, 247, 262, -1000, 168, - 269, -1000, -1000, 135, 126, 318, -1000, 216, 87, 86, - -1000, -59, -48, -60, -49, 175, -1000, 94, -1000, 113, - 32, 175, -1000, -1000, 124, -1000, 256, -1000, -23, -1000, - -51, -34, 207, -1000, 204, -74, -54, -1000, -1000, -1000, - -1000, -1000, -22, 290, -58, -62, 266, 254, 373, 135, - -65, -1000, -1000, -1000, -1000, -1000, -1000, 282, -1000, -1000, - 240, 113, 123, 335, -1000, -1000, 280, 249, 252, 175, - 29, -1000, 113, -1000, 247, 123, 123, 175, -1000, 14, - 243, -1000, 123, -1000, -1000, -1000, 243, -1000, + 310, -1000, -1000, -43, -1000, -1000, -1000, 322, -1000, -1000, + 354, 201, 360, 363, 316, 315, 279, 177, 243, 202, + 281, -1000, 310, -1000, 236, 236, 236, 355, -1000, 188, + 376, 183, 193, 182, 177, 177, 177, 297, -1000, 240, + -1000, -1000, 71, -1000, -1000, 174, 235, 169, 349, 236, + -1000, -1000, 372, 23, 23, -1000, 166, 80, 353, 29, + 27, 265, 147, 226, -1000, 278, -1000, 85, 148, -1000, + 26, 72, -1000, 230, 25, 165, 344, -1000, 23, 23, + -1000, 119, 130, 212, -1000, 119, 119, 22, -1000, -1000, + 119, -1000, -1000, -1000, -1000, -1000, 21, -1000, -1000, -1000, + -1000, -8, -1000, 7, 164, 332, 330, 331, 138, 138, + 382, 119, 106, -1000, 190, -1000, -45, 103, -1000, -1000, + 161, 79, 158, -1000, 156, 5, 157, -1000, -1000, 130, + 119, 119, 119, 119, 119, 119, 222, 233, 133, -1000, + 62, 50, 226, 54, 119, 119, 138, -1000, 156, 154, + 153, 149, -18, 84, -1000, -44, 256, 351, 130, 382, + 147, 119, 382, 376, 266, 4, 3, 148, 0, 148, + -1000, -19, -21, -1000, 78, -1000, 101, 138, -1, 50, + 50, 227, 227, 62, 20, -1000, 221, 119, -3, -1000, + -22, -1000, 173, -33, 77, 130, -51, -1000, -1000, 335, + -1000, 304, 146, 302, 254, 119, 343, 256, -1000, 130, + 194, 148, -34, 366, -35, -38, -1000, -1000, -1000, -1000, + 150, -66, -53, 138, -1000, 62, -14, -1000, 98, -1000, + 119, -1000, 145, -15, -1000, -15, -1000, 119, 130, -23, + 254, 265, -1000, 194, 275, -1000, -1000, 148, 139, 148, + 148, 326, -1000, 218, 95, -7, -1000, -54, -39, -56, + -48, 130, -1000, 110, -1000, 119, 75, 130, -1000, -1000, + 138, -1000, 263, -1000, -45, -1000, -49, -1000, -1000, -23, + 225, -1000, 216, -74, -55, -1000, -1000, -1000, -1000, -1000, + -15, 293, -58, -60, 271, 260, 382, 148, -71, -1000, + -1000, -1000, -1000, -1000, -1000, 289, -1000, -1000, 252, 119, + 111, 342, -1000, -1000, 284, 256, 258, 130, 70, -1000, + 119, -1000, 254, 111, 111, 130, -1000, 37, 247, -1000, + 111, -1000, -1000, -1000, 247, -1000, } var yyPgo = [...]int16{ - 0, 410, 353, 409, 408, 407, 16, 406, 405, 18, - 11, 8, 404, 403, 15, 7, 17, 12, 402, 9, - 20, 401, 400, 2, 399, 398, 10, 324, 19, 397, - 396, 175, 395, 13, 394, 393, 0, 14, 392, 391, - 390, 389, 3, 5, 388, 4, 387, 386, 1, 6, - 300, 385, 384, 383, 21, 382, 381, 380, + 0, 418, 360, 417, 416, 415, 16, 414, 413, 18, + 11, 8, 412, 411, 15, 7, 17, 12, 410, 9, + 20, 409, 408, 2, 407, 406, 10, 330, 19, 405, + 404, 194, 403, 13, 402, 401, 0, 14, 400, 399, + 398, 397, 3, 5, 396, 4, 395, 394, 1, 6, + 318, 393, 392, 391, 21, 390, 389, 382, } var yyR1 = [...]int8{ @@ -364,13 +365,13 @@ var yyR1 = [...]int8{ 18, 18, 18, 19, 8, 8, 9, 44, 44, 44, 51, 51, 52, 52, 52, 6, 6, 6, 6, 7, 25, 25, 24, 24, 21, 21, 22, 22, 20, 20, - 20, 23, 23, 26, 26, 26, 26, 27, 28, 29, - 29, 29, 30, 30, 30, 31, 31, 32, 32, 33, - 33, 34, 35, 35, 37, 37, 41, 41, 38, 38, - 42, 42, 43, 43, 47, 47, 49, 49, 46, 46, - 48, 48, 48, 45, 45, 45, 36, 36, 36, 36, - 36, 36, 36, 36, 39, 39, 39, 39, 53, 53, - 40, 40, 40, 40, 40, 40, 40, 40, + 20, 23, 23, 26, 26, 26, 26, 26, 26, 27, + 28, 29, 29, 29, 30, 30, 30, 31, 31, 32, + 32, 33, 33, 34, 35, 35, 37, 37, 41, 41, + 38, 38, 42, 42, 43, 43, 47, 47, 49, 49, + 46, 46, 48, 48, 48, 45, 45, 45, 36, 36, + 36, 36, 36, 36, 36, 36, 39, 39, 39, 39, + 53, 53, 40, 40, 40, 40, 40, 40, 40, 40, } var yyR2 = [...]int8{ @@ -383,13 +384,13 @@ var yyR2 = [...]int8{ 1, 1, 1, 4, 1, 3, 5, 0, 3, 3, 0, 1, 0, 1, 2, 1, 4, 2, 2, 13, 0, 1, 0, 1, 1, 1, 2, 4, 1, 4, - 4, 1, 3, 3, 4, 2, 6, 1, 2, 0, - 2, 2, 0, 2, 2, 2, 1, 0, 1, 1, - 2, 6, 0, 1, 0, 2, 0, 3, 0, 2, - 0, 2, 0, 2, 0, 3, 0, 4, 2, 4, - 0, 1, 1, 0, 1, 2, 1, 1, 2, 2, - 4, 4, 6, 6, 1, 1, 3, 3, 0, 1, - 3, 3, 3, 3, 3, 3, 3, 4, + 4, 1, 3, 3, 4, 4, 4, 2, 6, 1, + 2, 0, 2, 2, 0, 2, 2, 2, 1, 0, + 1, 1, 2, 6, 0, 1, 0, 2, 0, 3, + 0, 2, 0, 2, 0, 2, 0, 3, 0, 4, + 2, 4, 0, 1, 1, 0, 1, 2, 1, 1, + 2, 2, 4, 4, 6, 6, 1, 1, 3, 3, + 0, 1, 3, 3, 3, 3, 3, 3, 3, 4, } var yyChk = [...]int16{ @@ -409,59 +410,61 @@ var yyChk = [...]int16{ 87, 88, 90, 89, 74, 75, 63, -53, 67, 58, -36, -36, 93, -36, 93, 93, 93, 76, 25, 24, 25, 25, -12, -10, 76, -10, -49, 6, -36, -37, - 86, 75, -26, -27, 93, -19, 76, -20, 76, 89, - -23, 76, -8, -9, 76, 93, 76, -36, -36, -36, - -36, -36, -36, 65, 58, 59, 62, 77, -6, 94, - -36, -17, -16, -36, -10, -9, 76, 76, 76, 94, - 86, 94, -42, 50, 19, -49, -54, -36, -49, -28, - -6, 9, -45, -45, 94, 94, 86, 77, -10, 93, - 65, -36, 93, 94, 55, 94, 86, 94, 24, 35, - 76, 35, -43, 51, -36, 20, -42, -32, -33, -34, - -35, 73, -45, 94, 15, 26, -9, -44, 95, 93, - 94, -10, -6, -16, 77, -36, 76, -14, -15, 93, - -14, -36, -11, 76, 93, -43, -37, -33, 45, -45, - 76, 27, -52, 65, 58, 78, 78, 94, 94, 94, - 94, -56, 86, 20, -17, -10, -41, 48, -26, 94, - -11, -51, 64, 65, 96, 94, -15, 39, 94, 94, - -38, 46, 49, -49, -45, 94, 40, -47, 52, -36, - -13, -23, 20, 41, -42, 49, 86, -36, -43, -46, - -23, -23, 86, -48, 53, 54, -23, -48, + 86, 75, -26, -27, 93, 69, 70, -19, 76, -20, + 76, 89, -23, 76, -8, -9, 76, 93, 76, -36, + -36, -36, -36, -36, -36, 65, 58, 59, 62, 77, + -6, 94, -36, -17, -16, -36, -10, -9, 76, 76, + 76, 94, 86, 94, -42, 50, 19, -49, -54, -36, + -49, -28, -6, 9, 93, 93, -45, -45, 94, 94, + 86, 77, -10, 93, 65, -36, 93, 94, 55, 94, + 86, 94, 24, 35, 76, 35, -43, 51, -36, 20, + -42, -32, -33, -34, -35, 73, -45, 94, 15, 94, + 94, 26, -9, -44, 95, 93, 94, -10, -6, -16, + 77, -36, 76, -14, -15, 93, -14, -36, -11, 76, + 93, -43, -37, -33, 45, -45, 76, -45, -45, 27, + -52, 65, 58, 78, 78, 94, 94, 94, 94, -56, + 86, 20, -17, -10, -41, 48, -26, 94, -11, -51, + 64, 65, 96, 94, -15, 39, 94, 94, -38, 46, + 49, -49, -45, 94, 40, -47, 52, -36, -13, -23, + 20, 41, -42, 49, 86, -36, -43, -46, -23, -23, + 86, -48, 53, 54, -23, -48, } var yyDef = [...]int16{ 0, -2, 1, 4, 6, 7, 8, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 82, 2, 5, 9, 27, 27, 27, 0, 14, 0, - 99, 0, 0, 0, 0, 0, 0, 0, 97, 80, + 101, 0, 0, 0, 0, 0, 0, 0, 99, 80, 77, 78, 0, 83, 3, 0, 0, 0, 0, 27, - 15, 16, 102, 0, 0, 18, 0, 0, 0, 0, - 0, 114, 0, 0, 81, 0, 84, 85, 133, 88, - 0, 91, 13, 0, 0, 0, 0, 98, 0, 0, - 100, 0, 106, -2, 137, 0, 0, 0, 144, 145, + 15, 16, 104, 0, 0, 18, 0, 0, 0, 0, + 0, 116, 0, 0, 81, 0, 84, 85, 135, 88, + 0, 91, 13, 0, 0, 0, 0, 100, 0, 0, + 102, 0, 108, -2, 139, 0, 0, 0, 146, 147, 0, 53, 54, 55, 56, 57, 0, 59, 60, 61, - 62, 91, 101, 0, 0, 0, 0, 0, 40, 0, - 126, 0, 114, 37, 0, 76, 0, 0, 86, 134, - 0, 0, 0, 28, 0, 0, 0, 103, 104, 105, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, - 138, 139, 0, 0, 0, 49, 0, 22, 0, 0, - 0, 0, 0, 41, 45, 0, 120, 0, 115, 126, - 0, 0, 126, 99, 0, 133, 97, 133, 135, 0, - 0, 92, 0, 64, 0, 0, 0, 150, 151, 152, - 153, 154, 155, 156, 0, 0, 0, 147, 0, 146, - 0, 0, 50, 51, 0, 23, 24, 0, 26, 0, - 0, 0, 122, 0, 0, 120, 38, 39, -2, 133, - 0, 0, 95, 87, 89, 90, 0, 67, 0, 0, - 157, 140, 0, 141, 0, 63, 0, 21, 0, 0, - 46, 0, 33, 0, 121, 0, 122, 114, 108, -2, - 0, 113, 93, 133, 0, 0, 65, 72, 0, 0, - 19, 0, 0, 0, 0, 52, 25, 35, 42, 49, - 32, 123, 127, 29, 0, 34, 116, 110, 0, 94, - 0, 0, 70, 73, 0, 0, 0, 20, 142, 143, - 58, 31, 0, 0, 0, 0, 118, 0, 126, 133, - 0, 66, 71, 74, 68, 69, 43, 0, 44, 30, - 124, 0, 0, 0, 96, 17, 0, 120, 0, 119, - 117, 47, 0, 36, 122, 0, 0, 111, 79, 125, - 130, 48, 0, 128, 131, 132, 130, 129, + 62, 91, 103, 0, 0, 0, 0, 0, 40, 0, + 128, 0, 116, 37, 0, 76, 0, 0, 86, 136, + 0, 0, 0, 28, 0, 0, 0, 105, 106, 107, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, + 140, 141, 0, 0, 0, 49, 0, 22, 0, 0, + 0, 0, 0, 41, 45, 0, 122, 0, 117, 128, + 0, 0, 128, 101, 0, 0, 0, 135, 99, 135, + 137, 0, 0, 92, 0, 64, 0, 0, 0, 152, + 153, 154, 155, 156, 157, 158, 0, 0, 0, 149, + 0, 148, 0, 0, 50, 51, 0, 23, 24, 0, + 26, 0, 0, 0, 124, 0, 0, 122, 38, 39, + -2, 135, 0, 0, 0, 0, 97, 87, 89, 90, + 0, 67, 0, 0, 159, 142, 0, 143, 0, 63, + 0, 21, 0, 0, 46, 0, 33, 0, 123, 0, + 124, 116, 110, -2, 0, 115, 93, 135, 0, 135, + 135, 0, 65, 72, 0, 0, 19, 0, 0, 0, + 0, 52, 25, 35, 42, 49, 32, 125, 129, 29, + 0, 34, 118, 112, 0, 94, 0, 95, 96, 0, + 70, 73, 0, 0, 0, 20, 144, 145, 58, 31, + 0, 0, 0, 0, 120, 0, 128, 135, 0, 66, + 71, 74, 68, 69, 43, 0, 44, 30, 126, 0, + 0, 0, 98, 17, 0, 122, 0, 121, 119, 47, + 0, 36, 124, 0, 0, 113, 79, 127, 132, 48, + 0, 130, 133, 134, 132, 131, } var yyTok1 = [...]int8{ @@ -1304,316 +1307,326 @@ yydefault: yyVAL.ds = yyDollar[2].stmt.(DataSource) } case 95: + yyDollar = yyS[yypt-4 : yypt+1] + { + yyVAL.ds = &FnDataSourceStmt{fnCall: &FnCall{fn: "databases"}, as: yyDollar[4].id} + } + case 96: + yyDollar = yyS[yypt-4 : yypt+1] + { + yyVAL.ds = &FnDataSourceStmt{fnCall: &FnCall{fn: "tables"}, as: yyDollar[4].id} + } + case 97: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.ds = &FnDataSourceStmt{fnCall: yyDollar[1].value.(*FnCall), as: yyDollar[2].id} } - case 96: + case 98: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.ds = &tableRef{table: yyDollar[4].id, history: true, as: yyDollar[6].id} } - case 97: + case 99: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.tableRef = &tableRef{table: yyDollar[1].id} } - case 98: + case 100: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.period = period{start: yyDollar[1].openPeriod, end: yyDollar[2].openPeriod} } - case 99: + case 101: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.openPeriod = nil } - case 100: + case 102: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.openPeriod = &openPeriod{inclusive: true, instant: yyDollar[2].periodInstant} } - case 101: + case 103: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.openPeriod = &openPeriod{instant: yyDollar[2].periodInstant} } - case 102: + case 104: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.openPeriod = nil } - case 103: + case 105: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.openPeriod = &openPeriod{inclusive: true, instant: yyDollar[2].periodInstant} } - case 104: + case 106: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.openPeriod = &openPeriod{instant: yyDollar[2].periodInstant} } - case 105: + case 107: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.periodInstant = periodInstant{instantType: txInstant, exp: yyDollar[2].exp} } - case 106: + case 108: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.periodInstant = periodInstant{instantType: timeInstant, exp: yyDollar[1].exp} } - case 107: + case 109: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.joins = nil } - case 108: + case 110: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.joins = yyDollar[1].joins } - case 109: + case 111: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.joins = []*JoinSpec{yyDollar[1].join} } - case 110: + case 112: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.joins = append([]*JoinSpec{yyDollar[1].join}, yyDollar[2].joins...) } - case 111: + case 113: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.join = &JoinSpec{joinType: yyDollar[1].joinType, ds: yyDollar[3].ds, indexOn: yyDollar[4].ids, cond: yyDollar[6].exp} } - case 112: + case 114: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.joinType = InnerJoin } - case 113: + case 115: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.joinType = yyDollar[1].joinType } - case 114: + case 116: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 115: + case 117: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 116: + case 118: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.cols = nil } - case 117: + case 119: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.cols = yyDollar[3].cols } - case 118: + case 120: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 119: + case 121: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 120: + case 122: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 121: + case 123: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 122: + case 124: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.exp = nil } - case 123: + case 125: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 124: + case 126: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.ordcols = nil } - case 125: + case 127: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.ordcols = yyDollar[3].ordcols } - case 126: + case 128: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.ids = nil } - case 127: + case 129: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.ids = yyDollar[4].ids } - case 128: + case 130: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.ordcols = []*OrdCol{{sel: yyDollar[1].col, descOrder: yyDollar[2].opt_ord}} } - case 129: + case 131: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.ordcols = append(yyDollar[1].ordcols, &OrdCol{sel: yyDollar[3].col, descOrder: yyDollar[4].opt_ord}) } - case 130: + case 132: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.opt_ord = false } - case 131: + case 133: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.opt_ord = false } - case 132: + case 134: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.opt_ord = true } - case 133: + case 135: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.id = "" } - case 134: + case 136: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.id = yyDollar[1].id } - case 135: + case 137: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.id = yyDollar[2].id } - case 136: + case 138: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].exp } - case 137: + case 139: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].binExp } - case 138: + case 140: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = &NotBoolExp{exp: yyDollar[2].exp} } - case 139: + case 141: yyDollar = yyS[yypt-2 : yypt+1] { yyVAL.exp = &NumExp{left: &Integer{val: 0}, op: SUBSOP, right: yyDollar[2].exp} } - case 140: + case 142: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.exp = &LikeBoolExp{val: yyDollar[1].exp, notLike: yyDollar[2].boolean, pattern: yyDollar[4].exp} } - case 141: + case 143: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.exp = &ExistsBoolExp{q: (yyDollar[3].stmt).(DataSource)} } - case 142: + case 144: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.exp = &InSubQueryExp{val: yyDollar[1].exp, notIn: yyDollar[2].boolean, q: yyDollar[5].stmt.(*SelectStmt)} } - case 143: + case 145: yyDollar = yyS[yypt-6 : yypt+1] { yyVAL.exp = &InListExp{val: yyDollar[1].exp, notIn: yyDollar[2].boolean, values: yyDollar[5].values} } - case 144: + case 146: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].sel } - case 145: + case 147: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.exp = yyDollar[1].value } - case 146: + case 148: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.exp = yyDollar[2].exp } - case 147: + case 149: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.exp = &Cast{val: yyDollar[1].exp, t: yyDollar[3].sqlType} } - case 148: + case 150: yyDollar = yyS[yypt-0 : yypt+1] { yyVAL.boolean = false } - case 149: + case 151: yyDollar = yyS[yypt-1 : yypt+1] { yyVAL.boolean = true } - case 150: + case 152: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: ADDOP, right: yyDollar[3].exp} } - case 151: + case 153: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: SUBSOP, right: yyDollar[3].exp} } - case 152: + case 154: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: DIVOP, right: yyDollar[3].exp} } - case 153: + case 155: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &NumExp{left: yyDollar[1].exp, op: MULTOP, right: yyDollar[3].exp} } - case 154: + case 156: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &BinBoolExp{left: yyDollar[1].exp, op: yyDollar[2].logicOp, right: yyDollar[3].exp} } - case 155: + case 157: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: yyDollar[2].cmpOp, right: yyDollar[3].exp} } - case 156: + case 158: yyDollar = yyS[yypt-3 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: EQ, right: &NullValue{t: AnyType}} } - case 157: + case 159: yyDollar = yyS[yypt-4 : yypt+1] { yyVAL.binExp = &CmpBoolExp{left: yyDollar[1].exp, op: NE, right: &NullValue{t: AnyType}} From e5a62658654dd358afe656f76e937e1e3269fd86 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Sat, 28 Oct 2023 08:28:49 +0200 Subject: [PATCH 18/23] chore(pkg/server): pgsql server creation only when enabled Signed-off-by: Jeronimo Irazabal --- pkg/server/remote_storage_test.go | 1 + pkg/server/server.go | 17 +++++++++-------- pkg/server/servertest/server.go | 7 +++++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/pkg/server/remote_storage_test.go b/pkg/server/remote_storage_test.go index 297fc61f8e..ba431b816c 100644 --- a/pkg/server/remote_storage_test.go +++ b/pkg/server/remote_storage_test.go @@ -500,6 +500,7 @@ func TestRemoteStorageUsedForNewDB(t *testing.T) { s.WithOptions(DefaultOptions(). WithDir(dir). WithPort(0). + WithPgsqlServer(false). WithListener(bufconn.Listen(1024 * 1024)), ) diff --git a/pkg/server/server.go b/pkg/server/server.go index b924cdbeb6..0500f07bdc 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -250,15 +250,16 @@ func (s *ImmuServer) Initialize() error { protomodel.RegisterAuthorizationServiceServer(s.GrpcServer, &authenticationServiceImp{server: s}) grpc_prometheus.Register(s.GrpcServer) - s.PgsqlSrv = pgsqlsrv.New( - pgsqlsrv.Host(s.Options.Address), - pgsqlsrv.Port(s.Options.PgsqlServerPort), - pgsqlsrv.ImmudbPort(s.Listener.Addr().(*net.TCPAddr).Port), - pgsqlsrv.TLSConfig(s.Options.TLSConfig), - pgsqlsrv.Logger(s.Logger), - pgsqlsrv.DatabaseList(s.dbList), - ) if s.Options.PgsqlServer { + s.PgsqlSrv = pgsqlsrv.New( + pgsqlsrv.Host(s.Options.Address), + pgsqlsrv.Port(s.Options.PgsqlServerPort), + pgsqlsrv.ImmudbPort(s.Listener.Addr().(*net.TCPAddr).Port), + pgsqlsrv.TLSConfig(s.Options.TLSConfig), + pgsqlsrv.Logger(s.Logger), + pgsqlsrv.DatabaseList(s.dbList), + ) + if err = s.PgsqlSrv.Initialize(); err != nil { return err } diff --git a/pkg/server/servertest/server.go b/pkg/server/servertest/server.go index e058ef107a..1cca2af880 100644 --- a/pkg/server/servertest/server.go +++ b/pkg/server/servertest/server.go @@ -142,8 +142,11 @@ func (bs *BufconnServer) Stop() error { if err := bs.Server.Srv.CloseDatabases(); err != nil { return err } - if err := bs.Server.Srv.PgsqlSrv.Stop(); err != nil { - return err + + if bs.Server.Srv.PgsqlSrv != nil { + if err := bs.Server.Srv.PgsqlSrv.Stop(); err != nil { + return err + } } if bs.GrpcServer != nil { From 59212aa0eafdfbf96214dffc28d272469986cfa5 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 3 Nov 2023 17:20:45 +0100 Subject: [PATCH 19/23] chore(pkg/pgsql): tls support Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/cert/ca-cert.pem | 34 ++++++++++++++ pkg/pgsql/server/cert/ca-cert.srl | 1 + pkg/pgsql/server/cert/ca-key.pem | 52 ++++++++++++++++++++++ pkg/pgsql/server/cert/server-cert.pem | 34 ++++++++++++++ pkg/pgsql/server/cert/server-ext.cnf | 1 + pkg/pgsql/server/cert/server-key.pem | 52 ++++++++++++++++++++++ pkg/pgsql/server/cert/server-req.pem | 28 ++++++++++++ pkg/pgsql/server/initialize_session.go | 19 +++++++- pkg/pgsql/server/pgsql_integration_test.go | 32 ++++++------- 9 files changed, 233 insertions(+), 20 deletions(-) create mode 100644 pkg/pgsql/server/cert/ca-cert.pem create mode 100644 pkg/pgsql/server/cert/ca-cert.srl create mode 100644 pkg/pgsql/server/cert/ca-key.pem create mode 100644 pkg/pgsql/server/cert/server-cert.pem create mode 100644 pkg/pgsql/server/cert/server-ext.cnf create mode 100644 pkg/pgsql/server/cert/server-key.pem create mode 100644 pkg/pgsql/server/cert/server-req.pem diff --git a/pkg/pgsql/server/cert/ca-cert.pem b/pkg/pgsql/server/cert/ca-cert.pem new file mode 100644 index 0000000000..2052659b59 --- /dev/null +++ b/pkg/pgsql/server/cert/ca-cert.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF6TCCA9GgAwIBAgIUGH9hgmfEzEsRuSyq56bbVLZJSh8wDQYJKoZIhvcNAQEL +BQAwgYMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91 +c3RvbjETMBEGA1UECgwKQ29kZW5vdGFyeTEZMBcGA1UEAwwQKi5jb2Rlbm90YXJ5 +LmNvbTEiMCAGCSqGSIb3DQEJARYTaW5mb0Bjb2Rlbm90YXJ5LmNvbTAeFw0yMzEx +MDMxNTUxMDdaFw0zMzEwMzExNTUxMDdaMIGDMQswCQYDVQQGEwJVUzEOMAwGA1UE +CAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xEzARBgNVBAoMCkNvZGVub3Rhcnkx +GTAXBgNVBAMMECouY29kZW5vdGFyeS5jb20xIjAgBgkqhkiG9w0BCQEWE2luZm9A +Y29kZW5vdGFyeS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7 +uR3S6YWXUckguoZHeuoD4mUv7E+O74c8/5rJCu8xW5diFROZ3NB9MGRPnCoUSLam +qAXqO+FW0iwwWANlH1qQu3uJogOSVcx2qkne9cQ3PF5lG+O0l+6mu7I5tCLalkIe +BLVH0bxxSe/lqHfD1lYO6uq74MIs35zNYaX2A5en8tJ8FoA4sE1uNraThq+vx7Aq +hzNApEUD3GAqRyDUcvDcx/9WgogaVm5k+J2xk3Q3aKaVzVh0BisGD52SSMicQtYk +rtFK/tuYCXyWM7SOMtgRSPI0M01BqtYrC12zRpnYD3oNoao0QCv2gJylrs/j3hSD +pLFyRy/dFKUb35nsEzNsk4yuzS4NJ8KBSYyWK5wu+D64G+Tg4DVQCf5BpSJD1/Jw +UIjkK6UmedNr5CSbzzurifwXkMFJ08dYUdKr8b7XUVxSOrvbkGnzJgTM3/bh356L +DUFlKxTxLTsZqovn7Q5aUHtGe0lU7b48ZX/RzSYl3BliQ2efMURWzVRITh6+j+fz +ECK6MfXHH8pdvk4PxMNC/m70dZ2tZSNiyV3B0ngKRVJoF/9gKoQqQrlOgbFUNX1Z +BXv7o5vEMFkgTehOXM6jOkyfKqo/4TEO0StySet8miOYKtOGqWj4FzOSEc/48svE +nIeQfOPiK4NxEXwOLwjW2E2vzyAps4ZmlASHGfr8gwIDAQABo1MwUTAdBgNVHQ4E +FgQUUho7f1Gpfivi/wweuhE5HuEAO4cwHwYDVR0jBBgwFoAUUho7f1Gpfivi/wwe +uhE5HuEAO4cwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAAsnD +F3rwcVdBZJR9IzsViRvXstK0yfF8cdQE8uI6Hp9DzHOjHkdt2kBMrqRZNaxUdecd +i1Bt4/t43L/7tabNNxTI/Iubu9qAKZ6+oLJXpZAiKXWsob9eulA+8yZiG/LEzfpy +p6WkEPPNPNc1ISZk6o0KXoIBo0Yp1xwVuX/xTNgn2T//JBcuJ0b2PUOW+71sSlWH +tD6HVYcyDmpV3iKZLsLVaVvGQ3FEFMe8n+Hv/h1HRd7xTwX11dbKDLHWr25zNbKj +Ekv9u7ePSaO01FNeDqvQddmFQDwA6jgAPlogMO2/MOyBjHu7w6nQl3gjqrJkzJK0 +jQ1n74uhAwH7c7xrVyE3pW71vpV4nHK2LvzTh+UqtFy+MLFVhr+qCtB7R7NxqIcq +65KxznjqtMSK4+w3SMX2IqDX4lBJ0jMhENULPVsmYr1g4OPkdiLM8HV0YolZP7EZ +0yW2QABRIcH6Weqt3BvUIlqfsIBimyKSDLWzvKOYfOQWYhvwzqlGmNKUzrxeAIes +hLRHKCzkprSCqCh6zXgjG/lZD38exGbBj4TXFReTnqdF4SNNJTxDGe3lS2nr9RCI +E9m57ZttBbGDkRUs3OV1XW0XSGuvkDZaB1QoOBE5sbm4JBX2pfN9mdGeq/HXOCiv +qanwE0bUvzP9FQG1+4XPotP1CZVPoMegLPs5dZc= +-----END CERTIFICATE----- diff --git a/pkg/pgsql/server/cert/ca-cert.srl b/pkg/pgsql/server/cert/ca-cert.srl new file mode 100644 index 0000000000..5967b63c25 --- /dev/null +++ b/pkg/pgsql/server/cert/ca-cert.srl @@ -0,0 +1 @@ +46A407E210F53EBCE67145513C1202036E594946 diff --git a/pkg/pgsql/server/cert/ca-key.pem b/pkg/pgsql/server/cert/ca-key.pem new file mode 100644 index 0000000000..6fb0853d40 --- /dev/null +++ b/pkg/pgsql/server/cert/ca-key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC7uR3S6YWXUckg +uoZHeuoD4mUv7E+O74c8/5rJCu8xW5diFROZ3NB9MGRPnCoUSLamqAXqO+FW0iww +WANlH1qQu3uJogOSVcx2qkne9cQ3PF5lG+O0l+6mu7I5tCLalkIeBLVH0bxxSe/l +qHfD1lYO6uq74MIs35zNYaX2A5en8tJ8FoA4sE1uNraThq+vx7AqhzNApEUD3GAq +RyDUcvDcx/9WgogaVm5k+J2xk3Q3aKaVzVh0BisGD52SSMicQtYkrtFK/tuYCXyW +M7SOMtgRSPI0M01BqtYrC12zRpnYD3oNoao0QCv2gJylrs/j3hSDpLFyRy/dFKUb +35nsEzNsk4yuzS4NJ8KBSYyWK5wu+D64G+Tg4DVQCf5BpSJD1/JwUIjkK6UmedNr +5CSbzzurifwXkMFJ08dYUdKr8b7XUVxSOrvbkGnzJgTM3/bh356LDUFlKxTxLTsZ +qovn7Q5aUHtGe0lU7b48ZX/RzSYl3BliQ2efMURWzVRITh6+j+fzECK6MfXHH8pd +vk4PxMNC/m70dZ2tZSNiyV3B0ngKRVJoF/9gKoQqQrlOgbFUNX1ZBXv7o5vEMFkg +TehOXM6jOkyfKqo/4TEO0StySet8miOYKtOGqWj4FzOSEc/48svEnIeQfOPiK4Nx +EXwOLwjW2E2vzyAps4ZmlASHGfr8gwIDAQABAoICAC7BXZdBiH925FRdgMJe79hF +1BQKlIoySIm91AyMx6SQfnT0cOxanicAHYvihmyE69E4ejir72UTdeQYl8fg9kqk +F5HhI2iYLBPGOB3rMpLbW1tthdpeGRe4GhzbK+8ri440d/5KU9gXpUObITFKuiZ/ +BjYDNfm9PC2/S3mpzWUMSraTWB5GcxKnV/QIkMuEPfFpuS85euMKSX1eN+QSOMGU +opkma8W7j0Vg0s3+vuxqCUu4WHaVbrPUwddEf4rD7tg2HnTCY2lLu5chi6/7I+uy +Mnkj6fMYHL2d2Bml1P2GZUzt3hmjfg+oWtu9XZQQpSVgqL2g02AKG1GE8K5m3eCY +6k0CKrzuHc1OPSao1wGRXqQ8MVdfMivF0KgCZm36yFzJ1l0xuacXRsd7fYlFDAzL +lqm3AFXuThnMS5JxlR0WO1/Za7F4rLnTLHmyEPVM/cH/hKVCFsnSL72abJ2ySEzK +vF8oDJIk45QrtAsFkn2BtqhgPur4whYU3GoObSlr1ch3V4qtImgc/dkmpCsgIZ4B +SQQFI+XizJxtI2DJhpGSNe3EiZ61F05lt17HW8pmH1NnNYwy3mYNs5Jn2rSA2JcO +WrDtKsgDd39uZoaFNyqOLWRmm5bYszuOrR7pLHhMupRDYgOWX6TDO2OD2xD2UaxZ +wEZyl5U+tHiyhQOcYd+BAoIBAQDfnZ8C7fZWB5M4+bLwuSuqcc4AhJEBR9lyTook +Ke0sTeQXAPuMRw+XsCEGg/YVrOEZHUiUEwHxyREImrsKyGICt/akNLNHCP3auHix +ZxLO4rlClDNidNqQnQggp86mETGp9b1HG8xhAsvv2wfRL1ZyMTvtmy71L7ikDCBs +m5meUHvuJ76fQ25gwhqm8AOsjjLIV9rmRpEgHS/ItOrYe+sQmEugCfTyLMwtDYGE +0qiirXyb79K8iUP0S5WXQmWGfLv3GuYXYfS9RWu1O8JdCAnKx6D5ubtnf4y3SwA/ +ec04TwZDR+EcM40lCYZr8aJZsOkXhsnOYjcJ676R1pNlp7TDAoIBAQDW6M4hzIxO +SrluPlcNUOpslWrKsRqeBW2PIdj8qHkHisVfMzPCoE67pyF9HJTPGgvMnGp+PZC4 +2vExk+2fN9j0PFggDA9kLbZzzbwLY6uHEF5rnAJMbYbHoND/t4ZPURxerGatlles +TqSGI6gBHawjeFtsySxAlKzbgAl5KtFd8ewlAdYINgVB3R1lezjVpqfvF1iSxraJ +RUI0JrM8TejFulC/7HWzfK+zXwnX9TYHH9KF+3VaRemMB0RN1ZDUO4pW2XfVqrw+ +uyVMbhS1/F97kE7EkmRitFvFZpeWp8OacrDMfGlgayaKq0679XaWDQ+3c4G5shwH +4aYQXJ+qpB1BAoIBADIeoQJGFb1oiz3s8Yd06W2VfmetTtbrpLgzFFFQuGECwEnL +pZXmY39LMcvFDgYDrpwzbQ4LSJdJyrCUBbJAAX+8feKGEVytjkBUsnCIurV2KbHb +h7zclhRtreGr2uxr1CbU9myWtXNU7iK/g/wF0SldEaKK8rZv0MGsGiRdp8vNHEnf +zKDjuzyipNif2SL26DjxQBX24RZClHA25KBK/f/FMsYXFTimg8jhSxNbKAL2QYSt +9xzc40dBHbE+Z4UCNhsHg2TgRruZcK+5SjIR2CgEIHd4gqGK/B4lCFQx16Z0R+IS +nUj14P/ZJ7DQAuR5e3UTd+3zI4TsutTzNCxHr4MCggEAEFp4zROenZqMD7qIr0e3 +/vlDvhbJ+rpZAupFc7xyMUO7Dyp7RtUiCJ+IKdgR7syBl1lTtTWEHLz0W5xxGYuL +Y9JvtkiUpz/fQWKna4pzE/0H4lJlzmELP4eaP8s8Wi7G5OFjktP86ey2EksGTsdu +QOi4tEd+qY9ms/FDR0gd1HNDT/Ga0tchgUiNIxrEUWW0I7p4D/s1Cq8NgaBsRSt8 +igdKe8BHmJflWtXhjuBm8xXV1EI1ROBLDE/FP9L/iVbaiQ9VUhoC5xcgmHdL9ik1 +LtblV4n4P5aP4S6UXG95r/gIQhc5gY/FyAmPHThphLOLvZ75gSLvhR4Dn/0cXUTN +wQKCAQBWEOjMw1ymSAdC55zYT4VtNz/sq47YTa7KAZbqumagBINRDr4zquyB7A7c +lK4kLneO1oaXX2apaPJJBhaHIa4CM0xoJ8VI2RZpBYQhsnNl+JEkCkQ4As7Bz2tO +JSauDyFd2PjsPqHeJ7UZn3Yx3W3DLTS4rC/PtJM9ozB/iUlhy+f4k2f/Apd/1qDO +3eV++2lFtzVhHnm1jXKP1zXlhdW4akdoQWY6tfOGcT9mtlzhhEvUAWk6crQXjiuN +iSqNujcxgVTC+xMLbqsuotApysWsqU6wDkKi7blL2VPicw6c8VA7/81ndEgZPIaa +vwopAU/AmEZF2KGlf1bbRVoXxATi +-----END PRIVATE KEY----- diff --git a/pkg/pgsql/server/cert/server-cert.pem b/pkg/pgsql/server/cert/server-cert.pem new file mode 100644 index 0000000000..2d699715ec --- /dev/null +++ b/pkg/pgsql/server/cert/server-cert.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/pkg/pgsql/server/cert/server-ext.cnf b/pkg/pgsql/server/cert/server-ext.cnf new file mode 100644 index 0000000000..89146b3e8a --- /dev/null +++ b/pkg/pgsql/server/cert/server-ext.cnf @@ -0,0 +1 @@ +subjectAltName=DNS:*.immudb.com,IP:0.0.0.0 \ No newline at end of file diff --git a/pkg/pgsql/server/cert/server-key.pem b/pkg/pgsql/server/cert/server-key.pem new file mode 100644 index 0000000000..d33ab5c0b4 --- /dev/null +++ b/pkg/pgsql/server/cert/server-key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +bonieX/tWyj+V6l1vlkUwd4xTGas +-----END PRIVATE KEY----- diff --git a/pkg/pgsql/server/cert/server-req.pem b/pkg/pgsql/server/cert/server-req.pem new file mode 100644 index 0000000000..19c9385186 --- /dev/null +++ b/pkg/pgsql/server/cert/server-req.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEuzCCAqMCAQAwdjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYD +VQQHDAdIb3VzdG9uMQ8wDQYDVQQKDAZpbW11ZGIxFDASBgNVBAMMCyouaW1tdWRi +LmlvMR4wHAYJKoZIhvcNAQkBFg9pbmZvQGltbXVkYi5jb20wggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQDPX6u6QPeuv8k0EmYiG7eO3tvhvF4an/gvju+0 +sh0i936x890rMjXdSr0ll/rK3vfVVLDzM35gPllmdNu8jXJKRZLzUyQVcsxYleJV +fG3I0EdBHS0u0aew1TK0nHofGYEuVB40nb97SslpkCHxgOo4Fm53FKfT2l/BH4mb +5m/oHqg8D+Aq2g73oGsiMf4krEtJwKQ/+AhWFNhmdOh9P0vd8dLFZ4ZZs19m1xpP +f3lhGfvJAFR8HQ5/7a03msXUTNeAxhQmrC/dVanGsPATU0Q9Bh2bkAJrKpgYP5yU +7L3eXi0Bbx6EjQV0TnAToZV/otxF0roKMdB2vvGupambxekgCTV3ZuPSLN5kbAyx +8xzEhmkdBvgIxzEVpHae3WpW7JsFitvPrF0Uvesx5vR9y/CPJyHcJLbnTFbDXq3Z +w9GV8crs2TiG390D+tElU0/4x8ed76r1Fs8LkMKTISbGoC+OkqhRcAJ2S0/CaxMJ +eOTizZRKFXHZsTnR1sDwKug38g2v7QwRtvmOrOT10eXZxLIKd+tbNS/1m1Y0b5ia +ZCB1axMTyhv9Y6L6x6a/c34UQaSpMOTTg33D1DjhrRQNVd/ihINfVqQEkxZmnO+B +ftZwnnAy4PLkiUTeoQ1Wv+ewF8sffctN1vOrsol5/Hr6cqH12eG5AY+7Hd3NViGL +xTpvwwIDAQABoAAwDQYJKoZIhvcNAQELBQADggIBACgdPg5bolGkxeBktGS3m4t3 +ZN5bwn98ZO8CbcMSSKiFtgLT2ZdwN07O1y/KWN3LZLiqac83VGczA5FrQeJ3J2Yx +hd98C6Zda/xT8O4fgVzoL/QDIkVJFBAjHs+nIFTCBZMVI6kmiw/SMNrKPzL7Vl7Q +VPiPIpCB85pg1ZZadlakpimyxapT05Rww0EJI7DwXtd+GfaKNOsETUa0g7qFq1wI +7ko6vN2NF6sU+PK0zaD8HStyMSgFWpjQfjSwLOlzVFsOFbYqJ3JK8PeX84/ep6/6 +zI73pNNBeys9u8dR9OF8xmk1YhKQDtbPzD2mzyYZoyKI8KgzWkfm8/xR6V6yznDv +jBKEG0gjt8Hp9OVhno+B9/WZWzTZkzqN2VxdLlLOAq6gnHy3C7aiwfRMZ8Kir9XF +qfe7xXYQdCikO2O8jxxzLIP+lWk8B8F83yEK+A+BnN3yIi+A/v5DByrkUzRn78QU +qCqqeW4aSlrgdLmfThIkA7Om4fesgKKYaPfjdvzFtJyLqxw4PRbo1kHjmw5xqMob +qtuU6zVCzAiOxq+ENlJVrOo3eI0gaYastlWhsi57Maf9IHH+pmMzpS4CVg2nS0OB +wQ6oYqWWGH2xhXmgcFH+c/VXb/wYsgkMHiUuIeLCrxaTDQr2zF1cLhXFkuWBInnY +uyY9qqJ+0AdO49yENS3M +-----END CERTIFICATE REQUEST----- diff --git a/pkg/pgsql/server/initialize_session.go b/pkg/pgsql/server/initialize_session.go index 48ccacb061..5d8b3eefe4 100644 --- a/pkg/pgsql/server/initialize_session.go +++ b/pkg/pgsql/server/initialize_session.go @@ -20,6 +20,7 @@ import ( "bufio" "bytes" "context" + "crypto/tls" "encoding/binary" "errors" "fmt" @@ -30,6 +31,9 @@ import ( bm "github.com/codenotary/immudb/pkg/pgsql/server/bmessages" fm "github.com/codenotary/immudb/pkg/pgsql/server/fmessages" "github.com/codenotary/immudb/pkg/pgsql/server/pgmeta" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" ) @@ -166,10 +170,23 @@ func (s *session) HandleStartup(ctx context.Context) (err error) { return pserr.ErrPwNotprovided } + var transportCredentials credentials.TransportCredentials + + if s.tlsConfig == nil || s.tlsConfig.RootCAs == nil { + transportCredentials = insecure.NewCredentials() + } else { + config := &tls.Config{ + RootCAs: s.tlsConfig.RootCAs, + } + + transportCredentials = credentials.NewTLS(config) + } + opts := client.DefaultOptions(). WithAddress(s.immudbHost). WithPort(s.immudbPort). - WithDisableIdentityCheck(true) + WithDisableIdentityCheck(true). + WithDialOptions([]grpc.DialOption{grpc.WithTransportCredentials(transportCredentials)}) s.client = client.NewClient().WithOptions(opts) diff --git a/pkg/pgsql/server/pgsql_integration_test.go b/pkg/pgsql/server/pgsql_integration_test.go index a48bf9aadc..a4a8669277 100644 --- a/pkg/pgsql/server/pgsql_integration_test.go +++ b/pkg/pgsql/server/pgsql_integration_test.go @@ -19,6 +19,7 @@ package server_test import ( "context" "crypto/tls" + "crypto/x509" "database/sql" "encoding/hex" "fmt" @@ -604,28 +605,21 @@ func TestPgsqlServer_SimpleQueryQueryExecError(t *testing.T) { func TestPgsqlServer_SimpleQueryQuerySSLConn(t *testing.T) { td := t.TempDir() - certPem := []byte(`-----BEGIN CERTIFICATE----- -MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw -DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow -EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d -7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B -5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr -BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1 -NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l -Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc -6MF9+Yw1Yy0t ------END CERTIFICATE-----`) - - keyPem := []byte(`-----BEGIN EC PRIVATE KEY----- -MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49 -AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q -EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA== ------END EC PRIVATE KEY-----`) + pemServerCA, err := os.ReadFile("cert/ca-cert.pem") + require.NoError(t, err) - cert, err := tls.X509KeyPair(certPem, keyPem) + serverCert, err := tls.LoadX509KeyPair("cert/server-cert.pem", "cert/server-key.pem") require.NoError(t, err) - cfg := &tls.Config{Certificates: []tls.Certificate{cert}} + certPool := x509.NewCertPool() + if !certPool.AppendCertsFromPEM(pemServerCA) { + panic("failed to add client CA's certificate") + } + + cfg := &tls.Config{ + RootCAs: certPool, + Certificates: []tls.Certificate{serverCert}, + } options := server.DefaultOptions(). WithDir(td). From bab0935303e63d12821e31585322264e7ab60ea0 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Fri, 3 Nov 2023 17:40:45 +0100 Subject: [PATCH 20/23] chore(pkg/pgsql): single command complete message Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/query_machine.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/pgsql/server/query_machine.go b/pkg/pgsql/server/query_machine.go index 9d4c1cb37e..96e422504a 100644 --- a/pkg/pgsql/server/query_machine.go +++ b/pkg/pgsql/server/query_machine.go @@ -285,11 +285,11 @@ func (s *session) fetchAndWriteResults(statements string, parameters []*schema.N return err } } + } - _, err = s.writeMessage(bm.CommandComplete([]byte("ok"))) - if err != nil { - return err - } + _, err = s.writeMessage(bm.CommandComplete([]byte("ok"))) + if err != nil { + return err } return nil From e786e56f25a16d69fac2f8c459a5db51dc19a3b9 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Mon, 6 Nov 2023 10:04:49 +0100 Subject: [PATCH 21/23] test(pkg/pgsql): query machine protocol upgrade Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/server/query_machine_test.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pkg/pgsql/server/query_machine_test.go b/pkg/pgsql/server/query_machine_test.go index 15585063c8..ad546f201b 100644 --- a/pkg/pgsql/server/query_machine_test.go +++ b/pkg/pgsql/server/query_machine_test.go @@ -47,8 +47,6 @@ func TestSession_QueriesMachine(t *testing.T) { c2.Write([]byte("_")) unsupported := make([]byte, 500) c2.Read(unsupported) - ready4Query = make([]byte, len(bmessages.ReadyForQuery())) - c2.Read(ready4Query) c2.Close() }, out: nil, @@ -81,8 +79,6 @@ func TestSession_QueriesMachine(t *testing.T) { c2.Write(h.Msg('B', h.Join([][]byte{h.S("port"), h.S("wrong_st"), h.I16(1), h.I16(0), h.I16(1), h.I32(2), h.I16(1), h.I16(1), h.I16(1)}))) errst := make([]byte, 500) c2.Read(errst) - ready4Query = make([]byte, len(bmessages.ReadyForQuery())) - c2.Read(ready4Query) c2.Write(h.Msg('B', h.Join([][]byte{h.S("port"), h.S("st"), h.I16(1), h.I16(0), h.I16(1), h.I32(2), h.I16(1), h.I16(1), h.I16(1)}))) c2.Write(h.Msg('S', []byte{0})) ready4Query = make([]byte, len(bmessages.ReadyForQuery())) @@ -101,8 +97,6 @@ func TestSession_QueriesMachine(t *testing.T) { c2.Write(h.Msg('P', h.Join([][]byte{h.S("st"), h.S("wrong statement"), h.I16(1), h.I32(0)}))) errst := make([]byte, 500) c2.Read(errst) - ready4Query = make([]byte, len(bmessages.ReadyForQuery())) - c2.Read(ready4Query) // Terminate message c2.Write(h.Msg('X', []byte{0})) @@ -121,8 +115,6 @@ func TestSession_QueriesMachine(t *testing.T) { c2.Write(h.Msg('P', h.Join([][]byte{h.S("st"), h.S("set test"), h.I16(1), h.I32(0)}))) errst := make([]byte, 500) c2.Read(errst) - ready4Query = make([]byte, len(bmessages.ReadyForQuery())) - c2.Read(ready4Query) // Terminate message c2.Write(h.Msg('X', []byte{0})) From ed6903a1e677c7c56ccc67b10a386fdc14272e4f Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 7 Nov 2023 12:17:04 +0100 Subject: [PATCH 22/23] test(embedded/sql): cover pg_type reserved table Signed-off-by: Jeronimo Irazabal --- embedded/sql/engine_test.go | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/embedded/sql/engine_test.go b/embedded/sql/engine_test.go index d302511d78..dec881bc64 100644 --- a/embedded/sql/engine_test.go +++ b/embedded/sql/engine_test.go @@ -96,6 +96,13 @@ func TestUseDatabaseWithoutMultiDBHandler(t *testing.T) { _, err := engine.Query(context.Background(), nil, "SELECT * FROM DATABASES()", nil) require.ErrorIs(t, err, ErrUnspecifiedMultiDBHandler) }) + + r, err := engine.Query(context.Background(), nil, "SELECT ts FROM pg_type WHERE ts < 1 + NOW()", nil) + require.NoError(t, err) + defer r.Close() + + _, err = r.Read(context.Background()) + require.ErrorIs(t, err, ErrNoMoreRows) } func TestCreateTable(t *testing.T) { @@ -6017,6 +6024,25 @@ func TestMultiDBCatalogQueries(t *testing.T) { require.NoError(t, err) }) + t.Run("show databases", func(t *testing.T) { + r, err := engine.Query(context.Background(), nil, "SHOW DATABASES", nil) + require.NoError(t, err) + + for _, db := range dbs { + row, err := r.Read(context.Background()) + require.NoError(t, err) + require.NotNil(t, row) + require.NotNil(t, row) + require.Equal(t, db, row.ValuesBySelector["(databases.name)"].RawValue()) + } + + _, err = r.Read(context.Background()) + require.ErrorIs(t, err, ErrNoMoreRows) + + err = r.Close() + require.NoError(t, err) + }) + t.Run("query databases using conditions with table and column aliasing", func(t *testing.T) { r, err := engine.Query(context.Background(), nil, "SELECT dbs.name as dbname FROM DATABASES() as dbs WHERE name LIKE 'db*'", nil) require.NoError(t, err) @@ -6136,6 +6162,24 @@ func TestSingleDBCatalogQueries(t *testing.T) { require.ErrorIs(t, err, ErrNoMoreRows) }) + t.Run("show tables", func(t *testing.T) { + r, err := engine.Query(context.Background(), tx, "SHOW TABLES", nil) + require.NoError(t, err) + + defer r.Close() + + row, err := r.Read(context.Background()) + require.NoError(t, err) + require.Equal(t, "mytable1", row.ValuesBySelector["(tables.name)"].RawValue()) + + row, err = r.Read(context.Background()) + require.NoError(t, err) + require.Equal(t, "mytable2", row.ValuesBySelector["(tables.name)"].RawValue()) + + _, err = r.Read(context.Background()) + require.ErrorIs(t, err, ErrNoMoreRows) + }) + t.Run("unconditional index query should return all the indexes of mytable1", func(t *testing.T) { params := map[string]interface{}{ "tableName": "mytable1", From feefb30950105bd253463bd6e5a5b0e8449caea9 Mon Sep 17 00:00:00 2001 From: Jeronimo Irazabal Date: Tue, 7 Nov 2023 12:17:31 +0100 Subject: [PATCH 23/23] test(pkg/pgsql): unit testing for deallocate stmt Signed-off-by: Jeronimo Irazabal --- pkg/pgsql/errors/errors.go | 7 ------- pkg/pgsql/errors/errors_test.go | 2 -- pkg/pgsql/server/pgsql_integration_test.go | 3 +++ pkg/pgsql/server/query_machine.go | 6 ------ 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/pkg/pgsql/errors/errors.go b/pkg/pgsql/errors/errors.go index 3f790cf9e7..3d25789b27 100644 --- a/pkg/pgsql/errors/errors.go +++ b/pkg/pgsql/errors/errors.go @@ -34,7 +34,6 @@ var ErrExpectedQueryMessage = errors.New("expected query message") var ErrUseDBStatementNotSupported = errors.New("SQL statement not supported") var ErrSSLNotSupported = errors.New("SSL not supported") var ErrMaxStmtNumberExceeded = errors.New("maximum number of statements in a single query exceeded") -var ErrNoStatementFound = errors.New("no statement found") var ErrMessageCannotBeHandledInternally = errors.New("message cannot be handled internally") var ErrMaxParamsNumberExceeded = errors.New("number of parameters exceeded the maximum limit") var ErrParametersValueSizeTooLarge = errors.New("provided parameters exceeded the maximum allowed size limit") @@ -79,12 +78,6 @@ func MapPgError(err error) (er bm.ErrorResp) { bm.Message(err.Error()), bm.Hint("at the moment is possible to receive only 1 statement. Please split query or use a single statement"), ) - case errors.Is(err, ErrNoStatementFound): - er = bm.ErrorResponse(bm.Severity(pgmeta.PgSeverityError), - bm.Code(pgmeta.ProgramLimitExceeded), - bm.Message(err.Error()), - bm.Hint("provide at least one statement"), - ) case errors.Is(err, ErrParametersValueSizeTooLarge): er = bm.ErrorResponse(bm.Severity(pgmeta.PgSeverityError), bm.Code(pgmeta.DataException), diff --git a/pkg/pgsql/errors/errors_test.go b/pkg/pgsql/errors/errors_test.go index 1b4861f050..7978df8f40 100644 --- a/pkg/pgsql/errors/errors_test.go +++ b/pkg/pgsql/errors/errors_test.go @@ -29,8 +29,6 @@ func TestMapPgError(t *testing.T) { err = ErrMaxStmtNumberExceeded be = MapPgError(err) require.NotNil(t, be) - err = ErrNoStatementFound - be = MapPgError(err) require.NotNil(t, be) err = ErrParametersValueSizeTooLarge be = MapPgError(err) diff --git a/pkg/pgsql/server/pgsql_integration_test.go b/pkg/pgsql/server/pgsql_integration_test.go index a4a8669277..3b31b146dc 100644 --- a/pkg/pgsql/server/pgsql_integration_test.go +++ b/pkg/pgsql/server/pgsql_integration_test.go @@ -728,6 +728,9 @@ func TestPgsqlServer_VersionStatement(t *testing.T) { err = db.QueryRow("SELECT version()").Scan(&version) require.NoError(t, err) require.Equal(t, pgmeta.PgsqlProtocolVersionMessage, version) + + _, err = db.Exec("DEALLOCATE \"_PLAN0x7fb2c0822800\"") + require.NoError(t, err) } func TestPgsqlServerSetStatement(t *testing.T) { diff --git a/pkg/pgsql/server/query_machine.go b/pkg/pgsql/server/query_machine.go index 96e422504a..5fe5ac9c5e 100644 --- a/pkg/pgsql/server/query_machine.go +++ b/pkg/pgsql/server/query_machine.go @@ -103,12 +103,6 @@ func (s *session) QueryMachine() error { s.HandleError(pserr.ErrMaxStmtNumberExceeded) continue } - if len(stmts) == 0 { - waitForSync = extQueryMode - s.HandleError(pserr.ErrNoStatementFound) - continue - } - if paramCols, resCols, err = s.inferParamAndResultCols(stmts[0]); err != nil { waitForSync = extQueryMode s.HandleError(err)