File: params.go

package info (click to toggle)
usql 0.19.19-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,652 kB
  • sloc: sql: 1,115; sh: 643; ansic: 191; makefile: 60
file content (107 lines) | stat: -rw-r--r-- 2,322 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package stmt

import (
	"unicode"

	"github.com/xo/usql/text"
)

// Params holds information about command parameters.
type Params struct {
	R   []rune
	Len int
}

// DecodeParams decodes command parameters.
func DecodeParams(params string) *Params {
	r := []rune(params)
	return &Params{
		R:   r,
		Len: len(r),
	}
}

// GetRaw reads all remaining runes. No substitution or whitespace removal is
// performed.
func (p *Params) GetRaw() string {
	s := string(p.R)
	p.R, p.Len = p.R[:0], 0
	return s
}

// Get reads the next command parameter using the provided substitution func.
// True indicates there are runes remaining in the command parameters to
// process.
func (p *Params) Get(f func(string, bool) (bool, string, error)) (bool, string, error) {
	i, _ := findNonSpace(p.R, 0, p.Len)
	if i >= p.Len {
		return false, "", nil
	}
	var ok bool
	var quote rune
	start := i
loop:
	for ; i < p.Len; i++ {
		c, next := p.R[i], grab(p.R, i+1, p.Len)
		switch {
		case quote != 0:
			start := i - 1
			i, ok = readString(p.R, i, p.Len, quote, "")
			if !ok {
				break loop
			}
			ok, z, err := f(string(p.R[start:i+1]), false)
			switch {
			case err != nil:
				return false, "", err
			case ok:
				p.R, p.Len = substitute(p.R, start, p.Len, i-start+1, z)
				i = start + len(z) - 1
			}
			quote = 0
		// start of single, double, or backtick string
		case c == '\'' || c == '"' || c == '`':
			quote = c
		case c == ':' && next != ':':
			if v := readVar(p.R, i, p.Len); v != nil {
				n := v.String()
				ok, z, err := f(n[1:], true)
				switch {
				case err != nil:
					return false, "", err
				case ok:
					p.R, p.Len = substitute(p.R, v.I, p.Len, len(n), z)
					i = v.I + len(z) - 1
				default:
					i += len(n) - 1
				}
			}
		case unicode.IsSpace(c):
			break loop
		}
	}
	if quote != 0 {
		return false, "", text.ErrUnterminatedQuotedString
	}
	v := string(p.R[start:i])
	p.R = p.R[i:]
	p.Len = len(p.R)
	return true, v, nil
}

// GetAll retrieves all remaining command parameters using the provided
// substitution func. Will return on the first encountered error.
func (p *Params) GetAll(f func(string, bool) (bool, string, error)) ([]string, error) {
	var s []string
	for {
		ok, v, err := p.Get(f)
		if err != nil {
			return s, err
		}
		if !ok {
			break
		}
		s = append(s, v)
	}
	return s, nil
}