func findParams(sql string) ([]string, error) {
	const paramPrefix = '@'
	const singleQuote = '\''
	const doubleQuote = '"'
	const backtick = '`'
	isInQuoted := false
	var startQuote rune
	lastCharWasEscapeChar := false
	isTripleQuoted := false
	res := make([]string, 0)
	index := 0
	runes := []rune(sql)
	for index < len(runes) {
		c := runes[index]
		if isInQuoted {
			if (c == '\n' || c == '\r') && !isTripleQuoted {
				return nil, spanner.ToSpannerError(status.Errorf(codes.InvalidArgument, "statement contains an unclosed literal: %s", sql))
			} else if c == startQuote {
				if lastCharWasEscapeChar {
					lastCharWasEscapeChar = false
				} else if isTripleQuoted {
					if len(runes) > index+2 && runes[index+1] == startQuote && runes[index+2] == startQuote {
						isInQuoted = false
						startQuote = 0
						isTripleQuoted = false
						index += 2
					}
				} else {
					isInQuoted = false
					startQuote = 0
				}
			} else if c == '\\' {
				lastCharWasEscapeChar = true
			} else {
				lastCharWasEscapeChar = false
			}
		} else {
			// We are not in a quoted string. It's a parameter if it is an '@' followed by a letter or an underscore.
			// See https://cloud.google.com/spanner/docs/lexical#identifiers for identifier rules.
			if c == paramPrefix && len(runes) > index+1 && (unicode.IsLetter(runes[index+1]) || runes[index+1] == '_') {
				index++
				startIndex := index
				for index < len(runes) {
					if !(unicode.IsLetter(runes[index]) || unicode.IsDigit(runes[index]) || runes[index] == '_') {
						res = append(res, string(runes[startIndex:index]))
						break
					}
					if index == len(runes)-1 {
						res = append(res, string(runes[startIndex:]))
						break
					}
					index++
				}
			} else {
				if c == singleQuote || c == doubleQuote || c == backtick {
					isInQuoted = true
					startQuote = c
					// Check whether it is a triple-quote.
					if len(runes) > index+2 && runes[index+1] == startQuote && runes[index+2] == startQuote {
						isTripleQuoted = true
						index += 2
					}
				}
			}
		}
		index++
	}
	if isInQuoted {
		return nil, spanner.ToSpannerError(status.Errorf(codes.InvalidArgument, "statement contains an unclosed literal: %s", sql))
	}
	return res, nil
}
// This function assumes that all comments and statement hints have already
// been removed from the statement.
This function assumes that all comments and statement hints have already
been removed from the statement.
// This function assumes that all comments and statement hints have already // been removed from the statement .
func findParams(sql string) ([]string, error) {
	const paramPrefix = '@'
	const singleQuote = '\''
	const doubleQuote = '"'
	const backtick = '`'
	isInQuoted := false
	var startQuote rune
	lastCharWasEscapeChar := false
	isTripleQuoted := false
	res := make([]string, 0)
	index := 0
	runes := []rune(sql)
	for index < len(runes) {
		c := runes[index]
		if isInQuoted {
			if (c == '\n' || c == '\r') && !isTripleQuoted {
				return nil, spanner.ToSpannerError(status.Errorf(codes.InvalidArgument, "statement contains an unclosed literal: %s", sql))
			} else if c == startQuote {
				if lastCharWasEscapeChar {
					lastCharWasEscapeChar = false
				} else if isTripleQuoted {
					if len(runes) > index+2 && runes[index+1] == startQuote && runes[index+2] == startQuote {
						isInQuoted = false
						startQuote = 0
						isTripleQuoted = false
						index += 2
					}
				} else {
					isInQuoted = false
					startQuote = 0
				}
			} else if c == '\\' {
				lastCharWasEscapeChar = true
			} else {
				lastCharWasEscapeChar = false
			}
		} else {
			if c == paramPrefix && len(runes) > index+1 && (unicode.IsLetter(runes[index+1]) || runes[index+1] == '_') {
				index++
				startIndex := index
				for index < len(runes) {
					if !(unicode.IsLetter(runes[index]) || unicode.IsDigit(runes[index]) || runes[index] == '_') {
						res = append(res, string(runes[startIndex:index]))
						break
					}
					if index == len(runes)-1 {
						res = append(res, string(runes[startIndex:]))
						break
					}
					index++
				}
			} else {
				if c == singleQuote || c == doubleQuote || c == backtick {
					isInQuoted = true
					startQuote = c
					if len(runes) > index+2 && runes[index+1] == startQuote && runes[index+2] == startQuote {
						isTripleQuoted = true
						index += 2
					}
				}
			}
		}
		index++
	}
	if isInQuoted {
		return nil, spanner.ToSpannerError(status.Errorf(codes.InvalidArgument, "statement contains an unclosed literal: %s", sql))
	}
	return res, nil
}
func findParams ( sql string ) ( [ ] string , error ) { const paramPrefix = '@' const singleQuote = '\'' const doubleQuote = '"' const backtick = '`' isInQuoted := false var startQuote rune lastCharWasEscapeChar := false isTripleQuoted := false res := make ( [ ] string , 0 ) index := 0 runes := [ ] rune ( sql ) for index < len ( runes ) { c := runes [ index ] if isInQuoted { if ( c == '\n' || c == '\r' ) && ! isTripleQuoted { return nil , spanner . ToSpannerError ( status . Errorf ( codes . InvalidArgument , " " , sql ) ) } else if c == startQuote { if lastCharWasEscapeChar { lastCharWasEscapeChar = false } else if isTripleQuoted { if len ( runes ) > index + 2 && runes [ index + 1 ] == startQuote && runes [ index + 2 ] == startQuote { isInQuoted = false startQuote = 0 isTripleQuoted = false index += 2 } } else { isInQuoted = false startQuote = 0 } } else if c == '\\' { lastCharWasEscapeChar = true } else { lastCharWasEscapeChar = false } } else { if c == paramPrefix && len ( runes ) > index + 1 && ( unicode . IsLetter ( runes [ index + 1 ] ) || runes [ index + 1 ] == '_' ) { index ++ startIndex := index for index < len ( runes ) { if ! ( unicode . IsLetter ( runes [ index ] ) || unicode . IsDigit ( runes [ index ] ) || runes [ index ] == '_' ) { res = append ( res , string ( runes [ startIndex : index ] ) ) break } if index == len ( runes ) - 1 { res = append ( res , string ( runes [ startIndex : ] ) ) break } index ++ } } else { if c == singleQuote || c == doubleQuote || c == backtick { isInQuoted = true startQuote = c if len ( runes ) > index + 2 && runes [ index + 1 ] == startQuote && runes [ index + 2 ] == startQuote { isTripleQuoted = true index += 2 } } } } index ++ } if isInQuoted { return nil , spanner . ToSpannerError ( status . Errorf ( codes . InvalidArgument , " " , sql ) ) } return res , nil }
This function assumes that all comments and statement hints have already
been removed from the statement.
This function assumes that all comments and statement hints have already been removed from the statement .
// We are not in a quoted string. It's a parameter if it is an '@' followed by a letter or an underscore. // See https://cloud.google.com/spanner/docs/lexical#identifiers for identifier rules. // Check whether it is a triple-quote.