func ParseDSN()

in dsn.go [63:221]


func ParseDSN(dsn string) (*Config, error) {

	conf := &Config{
		maxRowsTotal:         -1,
		frameMaxSize:         -1,
		location:             time.UTC,
		transactionIsolation: 0,
		batching:             false,
	}

	parsed, err := url.ParseRequestURI(dsn)

	if err != nil {
		return nil, fmt.Errorf("unable to parse DSN: %w", err)
	}

	queries := parsed.Query()

	if v := queries.Get("maxRowsTotal"); v != "" {

		maxRowTotal, err := strconv.Atoi(v)

		if err != nil {
			return nil, fmt.Errorf("invalid value for maxRowsTotal: %w", err)
		}

		conf.maxRowsTotal = int64(maxRowTotal)
	}

	if v := queries.Get("frameMaxSize"); v != "" {

		maxRowTotal, err := strconv.Atoi(v)

		if err != nil {
			return nil, fmt.Errorf("invalid value for frameMaxSize: %w", err)
		}

		conf.frameMaxSize = int32(maxRowTotal)
	}

	if v := queries.Get("location"); v != "" {

		loc, err := time.LoadLocation(v)

		if err != nil {
			return nil, fmt.Errorf("invalid value for location: %w", err)
		}

		conf.location = loc
	}

	if v := queries.Get("transactionIsolation"); v != "" {

		isolation, err := strconv.Atoi(v)

		if err != nil {
			return nil, fmt.Errorf("invalid value for transactionIsolation: %w", err)
		}

		if isolation < 0 || isolation > 8 || isolation&(isolation-1) != 0 {
			return nil, fmt.Errorf("transactionIsolation must be 0, 1, 2, 4 or 8, %d given", isolation)
		}

		conf.transactionIsolation = uint32(isolation)
	}

	if v := queries.Get("batching"); v != "" {
		if v == "true" {
			conf.batching = true
		}
	}

	if v := queries.Get("authentication"); v != "" {

		auth := strings.ToUpper(v)

		if auth == "BASIC" {
			conf.authentication = basic
		} else if auth == "DIGEST" {
			conf.authentication = digest
		} else if auth == "SPNEGO" {
			conf.authentication = spnego
		} else {
			return nil, errors.New("authentication must be either BASIC, DIGEST or SPNEGO")
		}

		if conf.authentication == basic || conf.authentication == digest {

			user := queries.Get("avaticaUser")

			if user == "" {
				return nil, fmt.Errorf("authentication is set to %s, but avaticaUser is empty", v)
			}

			conf.avaticaUser = user

			pass := queries.Get("avaticaPassword")

			if pass == "" {
				return nil, fmt.Errorf("authentication is set to %s, but avaticaPassword is empty", v)
			}

			conf.avaticaPassword = pass

		} else if conf.authentication == spnego {
			principal := queries.Get("principal")

			keytab := queries.Get("keytab")

			krb5Conf := queries.Get("krb5Conf")

			krb5CredentialCache := queries.Get("krb5CredentialCache")

			if principal == "" && keytab == "" && krb5Conf == "" && krb5CredentialCache == "" {
				return nil, errors.New("when using SPNEGO authetication, you must provide the principal, keytab and krb5Conf parameters or a krb5TicketCache parameter")
			}

			if !((principal != "" && keytab != "" && krb5Conf != "") || (principal == "" && keytab == "" && krb5Conf == "")) {
				return nil, errors.New("when using SPNEGO authentication with a principal and keytab, the principal, keytab and krb5Conf parameters are required")
			}

			if (principal != "" || keytab != "" || krb5Conf != "") && krb5CredentialCache != "" {
				return nil, errors.New("ambigious configuration for SPNEGO authentication: use either principal, keytab and krb5Conf or krb5TicketCache")
			}

			if principal != "" {

				splittedPrincipal := strings.Split(principal, "@")

				if len(splittedPrincipal) != 2 {
					return nil, fmt.Errorf("invalid kerberos principal (%s): the principal should be in the format primary/instance@realm where instance is optional", principal)
				}

				conf.principal = krb5Principal{
					username: splittedPrincipal[0],
					realm:    splittedPrincipal[1],
				}

				conf.keytab = keytab
				conf.krb5Conf = krb5Conf
			} else if krb5CredentialCache != "" {
				conf.krb5CredentialCache = krb5CredentialCache
			}
		}
	}

	if parsed.Path != "" {
		s := strings.Split(parsed.Path, "/")
		conf.schema = s[len(s)-1]
	}

	parsed.User = nil
	parsed.RawQuery = ""
	parsed.Fragment = ""

	conf.endpoint = parsed.String()

	return conf, nil
}