| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 | package mssqlimport (	"bytes"	"io"	"strconv")type parser struct {	r          *bytes.Reader	w          bytes.Buffer	paramCount int	paramMax   int	// using map as a set	namedParams map [string]bool}func (p *parser) next() (rune, bool) {	ch, _, err := p.r.ReadRune()	if err != nil {		if err != io.EOF {			panic(err)		}		return 0, false	}	return ch, true}func (p *parser) unread() {	err := p.r.UnreadRune()	if err != nil {		panic(err)	}}func (p *parser) write(ch rune) {	p.w.WriteRune(ch)}type stateFunc func(*parser) stateFuncfunc parseParams(query string) (string, int) {	p := &parser{		r: bytes.NewReader([]byte(query)),		namedParams: map [string]bool{},	}	state := parseNormal	for state != nil {		state = state(p)	}	return p.w.String(), p.paramMax + len(p.namedParams)}func parseNormal(p *parser) stateFunc {	for {		ch, ok := p.next()		if !ok {			return nil		}		if ch == '?' {			return parseOrdinalParameter		} else if ch == '$' || ch == ':' {			ch2, ok := p.next()			if !ok {				p.write(ch)				return nil			}			p.unread()			if ch2 >= '0' && ch2 <= '9' {				return parseOrdinalParameter			} else if 'a' <= ch2 && ch2 <= 'z' || 'A' <= ch2 && ch2 <= 'Z' {				return parseNamedParameter			}		}		p.write(ch)		switch ch {		case '\'':			return parseQuote		case '"':			return parseDoubleQuote		case '[':			return parseBracket		case '-':			return parseLineComment		case '/':			return parseComment		}	}}func parseOrdinalParameter(p *parser) stateFunc {	var paramN int	var ok bool	for {		var ch rune		ch, ok = p.next()		if ok && ch >= '0' && ch <= '9' {			paramN = paramN*10 + int(ch-'0')		} else {			break		}	}	if ok {		p.unread()	}	if paramN == 0 {		p.paramCount++		paramN = p.paramCount	}	if paramN > p.paramMax {		p.paramMax = paramN	}	p.w.WriteString("@p")	p.w.WriteString(strconv.Itoa(paramN))	if !ok {		return nil	}	return parseNormal}func parseNamedParameter(p *parser) stateFunc {	var paramName string	var ok bool	for {		var ch rune		ch, ok = p.next()		if ok && (ch >= '0' && ch <= '9' || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') {			paramName = paramName + string(ch)		} else {			break		}	}	if ok {		p.unread()	}	p.namedParams[paramName] = true	p.w.WriteString("@")	p.w.WriteString(paramName)	if !ok {		return nil	}	return parseNormal}func parseQuote(p *parser) stateFunc {	for {		ch, ok := p.next()		if !ok {			return nil		}		p.write(ch)		if ch == '\'' {			return parseNormal		}	}}func parseDoubleQuote(p *parser) stateFunc {	for {		ch, ok := p.next()		if !ok {			return nil		}		p.write(ch)		if ch == '"' {			return parseNormal		}	}}func parseBracket(p *parser) stateFunc {	for {		ch, ok := p.next()		if !ok {			return nil		}		p.write(ch)		if ch == ']' {			ch, ok = p.next()			if !ok {				return nil			}			if ch != ']' {				p.unread()				return parseNormal			}			p.write(ch)		}	}}func parseLineComment(p *parser) stateFunc {	ch, ok := p.next()	if !ok {		return nil	}	if ch != '-' {		p.unread()		return parseNormal	}	p.write(ch)	for {		ch, ok = p.next()		if !ok {			return nil		}		p.write(ch)		if ch == '\n' {			return parseNormal		}	}}func parseComment(p *parser) stateFunc {	var nested int	ch, ok := p.next()	if !ok {		return nil	}	if ch != '*' {		p.unread()		return parseNormal	}	p.write(ch)	for {		ch, ok = p.next()		if !ok {			return nil		}		p.write(ch)		for ch == '*' {			ch, ok = p.next()			if !ok {				return nil			}			p.write(ch)			if ch == '/' {				if nested == 0 {					return parseNormal				} else {					nested--				}			}		}		for ch == '/' {			ch, ok = p.next()			if !ok {				return nil			}			p.write(ch)			if ch == '*' {				nested++			}		}	}}
 |