mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Lines delimiter.
This commit is contained in:
@@ -84,10 +84,11 @@ func (c *closure) BestIndex(idx *sqlite3.IndexInfo) error {
|
||||
cost := 1e7
|
||||
|
||||
for i, cst := range idx.Constraint {
|
||||
if !cst.Usable {
|
||||
switch {
|
||||
case !cst.Usable:
|
||||
continue
|
||||
}
|
||||
if plan&1 == 0 && cst.Column == _COL_ROOT {
|
||||
|
||||
case plan&1 == 0 && cst.Column == _COL_ROOT:
|
||||
switch cst.Op {
|
||||
case sqlite3.INDEX_CONSTRAINT_EQ:
|
||||
plan |= 1
|
||||
@@ -97,9 +98,8 @@ func (c *closure) BestIndex(idx *sqlite3.IndexInfo) error {
|
||||
Omit: true,
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if plan&0xf0 == 0 && cst.Column == _COL_DEPTH {
|
||||
|
||||
case plan&0xf0 == 0 && cst.Column == _COL_DEPTH:
|
||||
switch cst.Op {
|
||||
case sqlite3.INDEX_CONSTRAINT_LT, sqlite3.INDEX_CONSTRAINT_LE, sqlite3.INDEX_CONSTRAINT_EQ:
|
||||
plan |= posi << 4
|
||||
@@ -110,9 +110,8 @@ func (c *closure) BestIndex(idx *sqlite3.IndexInfo) error {
|
||||
plan |= 2
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if plan&0xf00 == 0 && cst.Column == _COL_TABLENAME {
|
||||
|
||||
case plan&0xf00 == 0 && cst.Column == _COL_TABLENAME:
|
||||
switch cst.Op {
|
||||
case sqlite3.INDEX_CONSTRAINT_EQ:
|
||||
plan |= posi << 8
|
||||
@@ -123,9 +122,8 @@ func (c *closure) BestIndex(idx *sqlite3.IndexInfo) error {
|
||||
Omit: true,
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if plan&0xf000 == 0 && cst.Column == _COL_IDCOLUMN {
|
||||
|
||||
case plan&0xf000 == 0 && cst.Column == _COL_IDCOLUMN:
|
||||
switch cst.Op {
|
||||
case sqlite3.INDEX_CONSTRAINT_EQ:
|
||||
plan |= posi << 12
|
||||
@@ -135,9 +133,8 @@ func (c *closure) BestIndex(idx *sqlite3.IndexInfo) error {
|
||||
Omit: true,
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if plan&0xf0000 == 0 && cst.Column == _COL_PARENTCOLUMN {
|
||||
|
||||
case plan&0xf0000 == 0 && cst.Column == _COL_PARENTCOLUMN:
|
||||
switch cst.Op {
|
||||
case sqlite3.INDEX_CONSTRAINT_EQ:
|
||||
plan |= posi << 16
|
||||
@@ -147,7 +144,6 @@ func (c *closure) BestIndex(idx *sqlite3.IndexInfo) error {
|
||||
Omit: true,
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ func RegisterFS(db *sqlite3.Conn, fsys fs.FS) error {
|
||||
return errors.Join(
|
||||
sqlite3.CreateModule(db, "lines", nil,
|
||||
func(db *sqlite3.Conn, _, _, _ string, _ ...string) (lines, error) {
|
||||
err := db.DeclareVTab(`CREATE TABLE x(line TEXT, data HIDDEN)`)
|
||||
err := db.DeclareVTab(`CREATE TABLE x(line TEXT, data HIDDEN, delim HIDDEN)`)
|
||||
if err == nil {
|
||||
err = db.VTabConfig(sqlite3.VTAB_INNOCUOUS)
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func RegisterFS(db *sqlite3.Conn, fsys fs.FS) error {
|
||||
}),
|
||||
sqlite3.CreateModule(db, "lines_read", nil,
|
||||
func(db *sqlite3.Conn, _, _, _ string, _ ...string) (lines, error) {
|
||||
err := db.DeclareVTab(`CREATE TABLE x(line TEXT, data HIDDEN)`)
|
||||
err := db.DeclareVTab(`CREATE TABLE x(line TEXT, data HIDDEN, delim HIDDEN)`)
|
||||
if err == nil {
|
||||
err = db.VTabConfig(sqlite3.VTAB_DIRECTONLY)
|
||||
}
|
||||
@@ -58,19 +58,29 @@ type lines struct {
|
||||
fsys fs.FS
|
||||
}
|
||||
|
||||
func (l lines) BestIndex(idx *sqlite3.IndexInfo) error {
|
||||
func (l lines) BestIndex(idx *sqlite3.IndexInfo) (err error) {
|
||||
err = sqlite3.CONSTRAINT
|
||||
for i, cst := range idx.Constraint {
|
||||
if cst.Column == 1 && cst.Op == sqlite3.INDEX_CONSTRAINT_EQ && cst.Usable {
|
||||
if !cst.Usable || cst.Op != sqlite3.INDEX_CONSTRAINT_EQ {
|
||||
continue
|
||||
}
|
||||
switch cst.Column {
|
||||
case 1:
|
||||
idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
|
||||
Omit: true,
|
||||
ArgvIndex: 1,
|
||||
}
|
||||
idx.EstimatedCost = 1e6
|
||||
idx.EstimatedRows = 100
|
||||
return nil
|
||||
err = nil
|
||||
case 2:
|
||||
idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
|
||||
Omit: true,
|
||||
ArgvIndex: 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
return sqlite3.CONSTRAINT
|
||||
return err
|
||||
}
|
||||
|
||||
func (l lines) Open() (sqlite3.VTabCursor, error) {
|
||||
@@ -85,6 +95,7 @@ type cursor struct {
|
||||
line []byte
|
||||
rowID int64
|
||||
eof bool
|
||||
delim byte
|
||||
}
|
||||
|
||||
func (c *cursor) EOF() bool {
|
||||
@@ -140,6 +151,15 @@ func (c *reader) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
|
||||
return fmt.Errorf("lines: unsupported argument:%.0w %v", sqlite3.MISMATCH, typ)
|
||||
}
|
||||
|
||||
c.delim = '\n'
|
||||
if len(arg) > 1 {
|
||||
b := arg[1].RawText()
|
||||
if len(b) != 1 {
|
||||
return fmt.Errorf("lines: delimiter must be a single byte%.0w", sqlite3.MISMATCH)
|
||||
}
|
||||
c.delim = b[0]
|
||||
}
|
||||
|
||||
c.reader = bufio.NewReader(r)
|
||||
c.closer, _ = r.(io.Closer)
|
||||
c.rowID = 0
|
||||
@@ -150,7 +170,12 @@ func (c *reader) Next() (err error) {
|
||||
c.line = c.line[:0]
|
||||
for more := true; more; {
|
||||
var line []byte
|
||||
line, more, err = c.reader.ReadLine()
|
||||
if c.delim == '\n' {
|
||||
line, more, err = c.reader.ReadLine()
|
||||
} else {
|
||||
line, err = c.reader.ReadSlice(c.delim)
|
||||
more = err == bufio.ErrBufferFull
|
||||
}
|
||||
c.line = append(c.line, line...)
|
||||
}
|
||||
if err == io.EOF {
|
||||
@@ -177,18 +202,27 @@ func (c *buffer) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
|
||||
return fmt.Errorf("lines: unsupported argument:%.0w %v", sqlite3.MISMATCH, typ)
|
||||
}
|
||||
|
||||
c.delim = '\n'
|
||||
if len(arg) > 1 {
|
||||
b := arg[1].RawText()
|
||||
if len(b) != 1 {
|
||||
return fmt.Errorf("lines: delimiter must be a single byte%.0w", sqlite3.MISMATCH)
|
||||
}
|
||||
c.delim = b[0]
|
||||
}
|
||||
|
||||
c.rowID = 0
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func (c *buffer) Next() error {
|
||||
i := bytes.IndexByte(c.data, '\n')
|
||||
i := bytes.IndexByte(c.data, c.delim)
|
||||
j := i + 1
|
||||
switch {
|
||||
case i < 0:
|
||||
i = len(c.data)
|
||||
j = i
|
||||
case i > 0 && c.data[i-1] == '\r':
|
||||
case i > 0 && c.delim == '\n' && c.data[i-1] == '\r':
|
||||
i--
|
||||
}
|
||||
c.eof = len(c.data) == 0
|
||||
|
||||
@@ -163,7 +163,7 @@ func Test_lines_test(t *testing.T) {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query(`SELECT rowid, line FROM lines_read(?)`, "lines_test.go")
|
||||
rows, err := db.Query(`SELECT rowid, line FROM lines_read(?, '}')`, "lines_test.go")
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
t.Skip(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user