github.com/icyphox/x@v0.0.355-0.20220311094250-029bd783e8b8/sqlcon/parse_opts.go (about) 1 package sqlcon 2 3 import ( 4 "fmt" 5 "net/url" 6 "strconv" 7 "strings" 8 "time" 9 10 "github.com/ory/x/logrusx" 11 ) 12 13 // ParseConnectionOptions parses values for max_conns, max_idle_conns, max_conn_lifetime from DSNs. 14 // It also returns the URI without those query parameters. 15 func ParseConnectionOptions(l *logrusx.Logger, dsn string) (maxConns int, maxIdleConns int, maxConnLifetime, maxIdleConnTime time.Duration, cleanedDSN string) { 16 maxConns = maxParallelism() * 2 17 maxIdleConns = maxParallelism() 18 maxConnLifetime = time.Duration(0) 19 maxIdleConnTime = time.Duration(0) 20 cleanedDSN = dsn 21 22 parts := strings.Split(dsn, "?") 23 if len(parts) != 2 { 24 l. 25 WithField("sql_max_connections", maxConns). 26 WithField("sql_max_idle_connections", maxIdleConns). 27 WithField("sql_max_connection_lifetime", maxConnLifetime). 28 WithField("sql_max_idle_connection_time", maxIdleConnTime). 29 Debugf("No SQL connection options have been defined, falling back to default connection options.") 30 return 31 } 32 33 query, err := url.ParseQuery(parts[1]) 34 if err != nil { 35 l. 36 WithField("sql_max_connections", maxConns). 37 WithField("sql_max_idle_connections", maxIdleConns). 38 WithField("sql_max_connection_lifetime", maxConnLifetime). 39 WithField("sql_max_idle_connection_time", maxIdleConnTime). 40 WithError(err). 41 Warnf("Unable to parse SQL DSN query, falling back to default connection options.") 42 return 43 } 44 45 if v := query.Get("max_conns"); v != "" { 46 s, err := strconv.ParseInt(v, 10, 64) 47 if err != nil { 48 l.WithError(err).Warnf(`SQL DSN query parameter "max_conns" value %v could not be parsed to int, falling back to default value %d`, v, maxConns) 49 } else { 50 maxConns = int(s) 51 } 52 query.Del("max_conns") 53 } 54 55 if v := query.Get("max_idle_conns"); v != "" { 56 s, err := strconv.ParseInt(v, 10, 64) 57 if err != nil { 58 l.WithError(err).Warnf(`SQL DSN query parameter "max_idle_conns" value %v could not be parsed to int, falling back to default value %d`, v, maxIdleConns) 59 } else { 60 maxIdleConns = int(s) 61 } 62 query.Del("max_idle_conns") 63 } 64 65 if v := query.Get("max_conn_lifetime"); v != "" { 66 s, err := time.ParseDuration(v) 67 if err != nil { 68 l.WithError(err).Warnf(`SQL DSN query parameter "max_conn_lifetime" value %v could not be parsed to duration, falling back to default value %d`, v, maxConnLifetime) 69 } else { 70 maxConnLifetime = s 71 } 72 query.Del("max_conn_lifetime") 73 } 74 75 if v := query.Get("max_conn_idle_time"); v != "" { 76 s, err := time.ParseDuration(v) 77 if err != nil { 78 l.WithError(err).Warnf(`SQL DSN query parameter "max_conn_idle_time" value %v could not be parsed to duration, falling back to default value %d`, v, maxIdleConnTime) 79 } else { 80 maxIdleConnTime = s 81 } 82 query.Del("max_conn_idle_time") 83 } 84 cleanedDSN = fmt.Sprintf("%s?%s", parts[0], query.Encode()) 85 86 return 87 } 88 89 // FinalizeDSN will return a finalized DSN URI. 90 func FinalizeDSN(l *logrusx.Logger, dsn string) string { 91 if strings.HasPrefix(dsn, "mysql://") { 92 var q url.Values 93 parts := strings.SplitN(dsn, "?", 2) 94 95 if len(parts) == 1 { 96 q = make(url.Values) 97 } else { 98 var err error 99 q, err = url.ParseQuery(parts[1]) 100 if err != nil { 101 l.WithError(err).Warnf("Unable to parse SQL DSN query, could not finalize the DSN URI.") 102 return dsn 103 } 104 } 105 106 q.Set("multiStatements", "true") 107 q.Set("parseTime", "true") 108 109 return fmt.Sprintf("%s?%s", parts[0], q.Encode()) 110 } 111 112 return dsn 113 }