url.go
func Parse(urlstr string) (*URL, error) {
	// parse url
	u, err := url.Parse(urlstr)
	if err != nil {
		return nil, err
	}
	if u.Scheme == "" {
		return nil, ErrInvalidDatabaseScheme
	}

	// create url
	v := &URL{URL: *u, OriginalScheme: urlstr[:len(u.Scheme)], Proto: "tcp"}

	// check for +protocol in scheme
	var checkProto bool
	if i := strings.IndexRune(v.Scheme, '+'); i != -1 {
		v.Proto = urlstr[i+1 : len(u.Scheme)]
		v.Scheme = v.Scheme[:i]
		checkProto = true
	}

	// get dsn generator
	scheme, ok := schemeMap[v.Scheme]
	if !ok {
		return nil, ErrUnknownDatabaseScheme
	}

	// if scheme does not understand opaque URLs, retry parsing after making a fully
	// qualified URL
	if !scheme.Opaque && v.Opaque != "" {
		q := ""
		if v.RawQuery != "" {
			q = "?" + v.RawQuery
		}
		f := ""
		if v.Fragment != "" {
			f = "#" + v.Fragment
		}

		return Parse(v.OriginalScheme + "://" + v.Opaque + q + f)
	}

	if scheme.Opaque && v.Opaque == "" {
		// force Opaque
		v.Opaque, v.Host, v.Path, v.RawPath = v.Host+v.Path, "", "", ""
	} else if v.Host == "." || (v.Host == "" && strings.TrimPrefix(v.Path, "/") != "") {
		// force unix proto
		v.Proto = "unix"
	}

	// check proto
	if checkProto || v.Proto != "tcp" {
		if scheme.Proto == ProtoNone {
			return nil, ErrInvalidTransportProtocol
		}

		switch {
		case scheme.Proto&ProtoAny != 0 && v.Proto != "":
		case scheme.Proto&ProtoTCP != 0 && v.Proto == "tcp":
		case scheme.Proto&ProtoUDP != 0 && v.Proto == "udp":
		case scheme.Proto&ProtoUnix != 0 && v.Proto == "unix":

		default:
			return nil, ErrInvalidTransportProtocol
		}
	}

	// set driver
	v.Driver = scheme.Driver
	v.Unaliased = scheme.Driver
	if scheme.Override != "" {
		v.Driver = scheme.Override
	}

	// generate dsn
	v.DSN, err = scheme.Generator(v)
	if err != nil {
		return nil, err
	}

	return v, nil
}
func Parse(urlstr string) (*URL, error) {
	// parse url
	u, err := url.Parse(urlstr)
	if err != nil {
		return nil, err
	}
	if u.Scheme == "" {
		return nil, ErrInvalidDatabaseScheme
	}

	// create url
	v := &URL{URL: *u, OriginalScheme: urlstr[:len(u.Scheme)], Proto: "tcp"}

	// check for +protocol in scheme
	var checkProto bool
	if i := strings.IndexRune(v.Scheme, '+'); i != -1 {
		v.Proto = urlstr[i+1 : len(u.Scheme)]
		v.Scheme = v.Scheme[:i]
		checkProto = true
	}

	// get dsn generator
	scheme, ok := schemeMap[v.Scheme]
	if !ok {
		return nil, ErrUnknownDatabaseScheme
	}

	// if scheme does not understand opaque URLs, retry parsing after making a fully
	// qualified URL
	if !scheme.Opaque && v.Opaque != "" {
		q := ""
		if v.RawQuery != "" {
			q = "?" + v.RawQuery
		}
		f := ""
		if v.Fragment != "" {
			f = "#" + v.Fragment
		}

		return Parse(v.OriginalScheme + "://" + v.Opaque + q + f)
	}

	if scheme.Opaque && v.Opaque == "" {
		// force Opaque
		v.Opaque, v.Host, v.Path, v.RawPath = v.Host+v.Path, "", "", ""
	} else if v.Host == "." || (v.Host == "" && strings.TrimPrefix(v.Path, "/") != "") {
		// force unix proto
		v.Proto = "unix"
	}

	// check proto
	if checkProto || v.Proto != "tcp" {
		if scheme.Proto == ProtoNone {
			return nil, ErrInvalidTransportProtocol
		}

		switch {
		case scheme.Proto&ProtoAny != 0 && v.Proto != "":
		case scheme.Proto&ProtoTCP != 0 && v.Proto == "tcp":
		case scheme.Proto&ProtoUDP != 0 && v.Proto == "udp":
		case scheme.Proto&ProtoUnix != 0 && v.Proto == "unix":

		default:
			return nil, ErrInvalidTransportProtocol
		}
	}

	// set driver
	v.Driver = scheme.Driver
	v.Unaliased = scheme.Driver
	if scheme.Override != "" {
		v.Driver = scheme.Override
	}

	// generate dsn
	v.DSN, err = scheme.Generator(v)
	if err != nil {
		return nil, err
	}

	return v, nil
}
// Parse parses urlstr, returning a URL with the OriginalScheme, Proto, Driver,
// Unaliased, and DSN fields populated.
//
// Note: if urlstr has a Opaque component (ie, URLs not specified as "scheme://"
// but "scheme:"), and the database scheme does not support opaque components,
// then Parse will attempt to re-process the URL as "scheme://<opaque>" using
// the OriginalScheme.