From 7fd6356a85e3d29944201e09b0e1cb0f4ba8aec1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 12 Jun 2021 15:06:05 +0800 Subject: [PATCH] Add DBVersion (#1723) Reviewed-on: https://gitea.com/xorm/xorm/pulls/1723 Co-authored-by: Lunny Xiao Co-committed-by: Lunny Xiao --- dialects/dialect.go | 1 + dialects/mssql.go | 25 +++++++++++++++++++++++++ dialects/mysql.go | 37 +++++++++++++++++++++++++++++++++++++ dialects/oracle.go | 20 ++++++++++++++++++++ dialects/postgres.go | 36 ++++++++++++++++++++++++++++++++++++ dialects/sqlite3.go | 21 +++++++++++++++++++++ engine.go | 12 +++--------- integrations/engine_test.go | 9 +++++++++ interface.go | 1 + schemas/version.go | 12 ++++++++++++ 10 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 schemas/version.go diff --git a/dialects/dialect.go b/dialects/dialect.go index 52655e6b..325836b4 100644 --- a/dialects/dialect.go +++ b/dialects/dialect.go @@ -44,6 +44,7 @@ type Dialect interface { URI() *URI SQLType(*schemas.Column) string FormatBytes(b []byte) string + Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) IsReserved(string) bool Quoter() schemas.Quoter diff --git a/dialects/mssql.go b/dialects/mssql.go index 32e7ac50..7e922e62 100644 --- a/dialects/mssql.go +++ b/dialects/mssql.go @@ -253,6 +253,31 @@ func (db *mssql) SetParams(params map[string]string) { } } +func (db *mssql) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) { + rows, err := queryer.QueryContext(ctx, + "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel') AS ProductLevel, SERVERPROPERTY ('edition') AS ProductEdition") + if err != nil { + return nil, err + } + defer rows.Close() + + var version, level, edition string + if !rows.Next() { + return nil, errors.New("unknow version") + } + + if err := rows.Scan(&version, &level, &edition); err != nil { + return nil, err + } + + // MSSQL: Microsoft SQL Server 2017 (RTM-CU13) (KB4466404) - 14.0.3048.4 (X64) Nov 30 2018 12:57:58 Copyright (C) 2017 Microsoft Corporation Developer Edition (64-bit) on Linux (Ubuntu 16.04.5 LTS) + return &schemas.Version{ + Number: version, + Level: level, + Edition: edition, + }, nil +} + func (db *mssql) SQLType(c *schemas.Column) string { var res string switch t := c.SQLType.Name; t { diff --git a/dialects/mysql.go b/dialects/mysql.go index 2b530daf..a169b901 100644 --- a/dialects/mysql.go +++ b/dialects/mysql.go @@ -188,6 +188,43 @@ func (db *mysql) Init(uri *URI) error { return db.Base.Init(db, uri) } +func (db *mysql) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) { + rows, err := queryer.QueryContext(ctx, "SELECT @@VERSION") + if err != nil { + return nil, err + } + defer rows.Close() + + var version string + if !rows.Next() { + return nil, errors.New("Unknow version") + } + + if err := rows.Scan(&version); err != nil { + return nil, err + } + + fields := strings.Split(version, "-") + if len(fields) == 3 && fields[1] == "TiDB" { + // 5.7.25-TiDB-v3.0.3 + return &schemas.Version{ + Number: strings.TrimPrefix(fields[2], "v"), + Level: fields[0], + Edition: fields[1], + }, nil + } + + var edition string + if len(fields) == 2 { + edition = fields[1] + } + + return &schemas.Version{ + Number: fields[0], + Edition: edition, + }, nil +} + func (db *mysql) SetParams(params map[string]string) { rowFormat, ok := params["rowFormat"] if ok { diff --git a/dialects/oracle.go b/dialects/oracle.go index 72bbe54d..0b06c4c6 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -515,6 +515,26 @@ func (db *oracle) Init(uri *URI) error { return db.Base.Init(db, uri) } +func (db *oracle) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) { + rows, err := queryer.QueryContext(ctx, "select * from v$version where banner like 'Oracle%'") + if err != nil { + return nil, err + } + defer rows.Close() + + var version string + if !rows.Next() { + return nil, errors.New("unknow version") + } + + if err := rows.Scan(&version); err != nil { + return nil, err + } + return &schemas.Version{ + Number: version, + }, nil +} + func (db *oracle) SQLType(c *schemas.Column) string { var res string switch t := c.SQLType.Name; t { diff --git a/dialects/postgres.go b/dialects/postgres.go index 544c98e9..52c88567 100644 --- a/dialects/postgres.go +++ b/dialects/postgres.go @@ -788,6 +788,42 @@ func (db *postgres) Init(uri *URI) error { return db.Base.Init(db, uri) } +func (db *postgres) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) { + rows, err := queryer.QueryContext(ctx, "SELECT version()") + if err != nil { + return nil, err + } + defer rows.Close() + + var version string + if !rows.Next() { + return nil, errors.New("Unknow version") + } + + if err := rows.Scan(&version); err != nil { + return nil, err + } + + // Postgres: 9.5.22 on x86_64-pc-linux-gnu (Debian 9.5.22-1.pgdg90+1), compiled by gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516, 64-bit + // CockroachDB CCL v19.2.4 (x86_64-unknown-linux-gnu, built + if strings.HasPrefix(version, "CockroachDB") { + versions := strings.Split(strings.TrimPrefix(version, "CockroachDB CCL "), " ") + return &schemas.Version{ + Number: strings.TrimPrefix(versions[0], "v"), + Edition: "CockroachDB", + }, nil + } else if strings.HasPrefix(version, "PostgreSQL") { + versions := strings.Split(strings.TrimPrefix(version, "PostgreSQL "), " on ") + return &schemas.Version{ + Number: versions[0], + Level: versions[1], + Edition: "PostgreSQL", + }, nil + } + + return nil, errors.New("unknow database version") +} + func (db *postgres) getSchema() string { if db.uri.Schema != "" { return db.uri.Schema diff --git a/dialects/sqlite3.go b/dialects/sqlite3.go index 82683606..a42aad48 100644 --- a/dialects/sqlite3.go +++ b/dialects/sqlite3.go @@ -160,6 +160,27 @@ func (db *sqlite3) Init(uri *URI) error { return db.Base.Init(db, uri) } +func (db *sqlite3) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) { + rows, err := queryer.QueryContext(ctx, "SELECT sqlite_version()") + if err != nil { + return nil, err + } + defer rows.Close() + + var version string + if !rows.Next() { + return nil, errors.New("Unknow version") + } + + if err := rows.Scan(&version); err != nil { + return nil, err + } + return &schemas.Version{ + Number: version, + Edition: "sqlite", + }, nil +} + func (db *sqlite3) SetQuotePolicy(quotePolicy QuotePolicy) { switch quotePolicy { case QuotePolicyNone: diff --git a/engine.go b/engine.go index d49eea9a..649ec1a2 100644 --- a/engine.go +++ b/engine.go @@ -925,15 +925,9 @@ func (engine *Engine) Having(conditions string) *Session { return session.Having(conditions) } -// Table table struct -type Table struct { - *schemas.Table - Name string -} - -// IsValid if table is valid -func (t *Table) IsValid() bool { - return t.Table != nil && len(t.Name) > 0 +// DBVersion returns the database version +func (engine *Engine) DBVersion() (*schemas.Version, error) { + return engine.dialect.Version(engine.defaultContext, engine.db) } // TableInfo get table info according to bean's content diff --git a/integrations/engine_test.go b/integrations/engine_test.go index 3b843f16..9b70f9b5 100644 --- a/integrations/engine_test.go +++ b/integrations/engine_test.go @@ -200,3 +200,12 @@ func TestImport(t *testing.T) { assert.NoError(t, err) assert.NoError(t, sess.Commit()) } + +func TestDBVersion(t *testing.T) { + assert.NoError(t, PrepareEngine()) + + version, err := testEngine.DBVersion() + assert.NoError(t, err) + + fmt.Println(testEngine.Dialect().URI().DBType, "version is", version) +} diff --git a/interface.go b/interface.go index 55162c8c..d31323ff 100644 --- a/interface.go +++ b/interface.go @@ -83,6 +83,7 @@ type EngineInterface interface { Context(context.Context) *Session CreateTables(...interface{}) error DBMetas() ([]*schemas.Table, error) + DBVersion() (*schemas.Version, error) Dialect() dialects.Dialect DriverName() string DropTables(...interface{}) error diff --git a/schemas/version.go b/schemas/version.go new file mode 100644 index 00000000..ba789679 --- /dev/null +++ b/schemas/version.go @@ -0,0 +1,12 @@ +// Copyright 2021 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package schemas + +// Version represents a database version +type Version struct { + Number string // the version number which could be compared + Level string + Edition string +}