You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			111 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
		
		
			
		
	
	
			111 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
| 
											5 months ago
										 | package gokb | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"context" | ||
|  | 	"database/sql/driver" | ||
|  | 	"errors" | ||
|  | 	"fmt" | ||
|  | 	"os" | ||
|  | 	"strings" | ||
|  | ) | ||
|  | 
 | ||
|  | // Connector represents a fixed configuration for the kb driver with a given
 | ||
|  | // name. Connector satisfies the database/sql/driver Connector interface and
 | ||
|  | // can be used to create any number of DB Conn's via the database/sql OpenDB
 | ||
|  | // function.
 | ||
|  | //
 | ||
|  | // See https://golang.org/pkg/database/sql/driver/#Connector.
 | ||
|  | // See https://golang.org/pkg/database/sql/#OpenDB.
 | ||
|  | type Connector struct { | ||
|  | 	opts   values | ||
|  | 	dialer Dialer | ||
|  | } | ||
|  | 
 | ||
|  | // Connect returns a connection to the database using the fixed configuration
 | ||
|  | // of this Connector. Context is not used.
 | ||
|  | func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { | ||
|  | 	return c.open(ctx) | ||
|  | } | ||
|  | 
 | ||
|  | // Driver returnst the underlying driver of this Connector.
 | ||
|  | func (c *Connector) Driver() driver.Driver { | ||
|  | 	return &Driver{} | ||
|  | } | ||
|  | 
 | ||
|  | // NewConnector returns a connector for the kb driver in a fixed configuration
 | ||
|  | // with the given dsn. The returned connector can be used to create any number
 | ||
|  | // of equivalent Conn's. The returned connector is intended to be used with
 | ||
|  | // database/sql.OpenDB.
 | ||
|  | //
 | ||
|  | // See https://golang.org/pkg/database/sql/driver/#Connector.
 | ||
|  | // See https://golang.org/pkg/database/sql/#OpenDB.
 | ||
|  | func NewConnector(dsn string) (*Connector, error) { | ||
|  | 	var err error | ||
|  | 	o := make(values) | ||
|  | 
 | ||
|  | 	// A number of defaults are applied here, in this order:
 | ||
|  | 	//
 | ||
|  | 	// * Very low precedence defaults applied in every situation
 | ||
|  | 	// * Environment variables
 | ||
|  | 	// * Explicitly passed connection information
 | ||
|  | 	o["host"] = "localhost" | ||
|  | 	o["port"] = "54321" | ||
|  | 	// N.B.: Extra float digits should be set to 3, but that breaks
 | ||
|  | 	// Kingbase 8.4 and older, where the max is 2.
 | ||
|  | 	o["extra_float_digits"] = "2" | ||
|  | 	for k, v := range parseEnviron(os.Environ()) { | ||
|  | 		o[k] = v | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if strings.HasPrefix(dsn, "kingbase://") || strings.HasPrefix(dsn, "kingbase://") { | ||
|  | 		dsn, err = ParseURL(dsn) | ||
|  | 		if err != nil { | ||
|  | 			return nil, err | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if err := parseOpts(dsn, o); err != nil { | ||
|  | 		return nil, err | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// Use the "fallback" application name if necessary
 | ||
|  | 	if fallback, ok := o["fallback_application_name"]; ok { | ||
|  | 		if _, ok := o["application_name"]; !ok { | ||
|  | 			o["application_name"] = fallback | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// We can't work with any client_encoding other than UTF-8 currently.
 | ||
|  | 	// However, we have historically allowed the user to set it to UTF-8
 | ||
|  | 	// explicitly, and there's no reason to break such programs, so allow that.
 | ||
|  | 	// Note that the "options" setting could also set client_encoding, but
 | ||
|  | 	// parsing its value is not worth it.  Instead, we always explicitly send
 | ||
|  | 	// client_encoding as a separate run-time parameter, which should override
 | ||
|  | 	// anything set in options.
 | ||
|  | 	if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) { | ||
|  | 		return nil, errors.New("client_encoding must be absent or 'UTF8'") | ||
|  | 	} | ||
|  | 	o["client_encoding"] = "UTF8" | ||
|  | 	// DateStyle needs a similar treatment.
 | ||
|  | 	if datestyle, ok := o["datestyle"]; ok { | ||
|  | 		if datestyle != "ISO, MDY" { | ||
|  | 			return nil, fmt.Errorf("setting datestyle must be absent or %v; got %v", "ISO, MDY", datestyle) | ||
|  | 		} | ||
|  | 	} else { | ||
|  | 		o["datestyle"] = "ISO, MDY" | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// If a user is not provided by any other means, the last
 | ||
|  | 	// resort is to use the current operating system provided user
 | ||
|  | 	// name.
 | ||
|  | 	if _, ok := o["user"]; !ok { | ||
|  | 		u, err := userCurrent() | ||
|  | 		if err != nil { | ||
|  | 			return nil, err | ||
|  | 		} | ||
|  | 		o["user"] = u | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return &Connector{opts: o, dialer: defaultDialer{}}, nil | ||
|  | } |