github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/crdb/version.go (about) 1 package crdb 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "regexp" 8 "strconv" 9 10 "github.com/jackc/pgx/v5" 11 "github.com/jackc/pgx/v5/pgconn" 12 "github.com/rs/zerolog" 13 14 pgxcommon "github.com/authzed/spicedb/internal/datastore/postgres/common" 15 ) 16 17 const ( 18 queryVersionJSON = "SELECT crdb_internal.active_version()::jsonb;" 19 queryVersion = "SELECT version();" 20 21 errFunctionDoesNotExist = "42883" 22 ) 23 24 var versionRegex = regexp.MustCompile(`v([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?`) 25 26 func queryServerVersion(ctx context.Context, db pgxcommon.DBFuncQuerier, version *crdbVersion) error { 27 if err := db.QueryRowFunc(ctx, func(ctx context.Context, row pgx.Row) error { 28 return row.Scan(version) 29 }, queryVersionJSON); err != nil { 30 var pgerr *pgconn.PgError 31 if !errors.As(err, &pgerr) || pgerr.Code != errFunctionDoesNotExist { 32 return err 33 } 34 35 // The crdb_internal.active_version() wasn't added until v22.1.X, try to parse the version 36 var versionStr string 37 if err := db.QueryRowFunc(ctx, func(ctx context.Context, row pgx.Row) error { 38 return row.Scan(&versionStr) 39 }, queryVersion); err != nil { 40 return err 41 } 42 43 return parseVersionStringInto(versionStr, version) 44 } 45 46 return nil 47 } 48 49 func parseVersionStringInto(versionStr string, version *crdbVersion) error { 50 found := versionRegex.FindStringSubmatch(versionStr) 51 if found == nil { 52 return fmt.Errorf("could not parse version from string: %s", versionStr) 53 } 54 55 var err error 56 version.Major, err = strconv.Atoi(found[1]) 57 if err != nil { 58 return fmt.Errorf("invalid major version: %s", found[1]) 59 } 60 version.Minor, err = strconv.Atoi(found[2]) 61 if err != nil { 62 return fmt.Errorf("invalid minor version: %s", found[2]) 63 } 64 version.Patch, err = strconv.Atoi(found[3]) 65 if err != nil { 66 return fmt.Errorf("invalid patch version: %s", found[3]) 67 } 68 69 return nil 70 } 71 72 type crdbVersion struct { 73 Internal int `json:"internal"` 74 Major int `json:"major"` 75 Minor int `json:"minor"` 76 Patch int `json:"patch"` 77 } 78 79 func (v crdbVersion) MarshalZerologObject(e *zerolog.Event) { 80 e.Int("major", v.Major).Int("minor", v.Minor).Int("patch", v.Patch) 81 }