github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/ext/array/array.go (about)

     1  // Package array provides the array table-valued SQL function.
     2  //
     3  // https://sqlite.org/carray.html
     4  package array
     5  
     6  import (
     7  	"fmt"
     8  	"reflect"
     9  
    10  	"github.com/ncruces/go-sqlite3"
    11  	"github.com/ncruces/go-sqlite3/internal/util"
    12  )
    13  
    14  // Register registers the array single-argument, table-valued SQL function.
    15  // The argument must be bound to a Go slice or array of
    16  // ints, floats, bools, strings or byte slices,
    17  // using [sqlite3.BindPointer] or [sqlite3.Pointer].
    18  func Register(db *sqlite3.Conn) {
    19  	sqlite3.CreateModule[array](db, "array", nil,
    20  		func(db *sqlite3.Conn, _, _, _ string, _ ...string) (array, error) {
    21  			err := db.DeclareVTab(`CREATE TABLE x(value, array HIDDEN)`)
    22  			return array{}, err
    23  		})
    24  }
    25  
    26  type array struct{}
    27  
    28  func (array) BestIndex(idx *sqlite3.IndexInfo) error {
    29  	for i, cst := range idx.Constraint {
    30  		if cst.Column == 1 && cst.Op == sqlite3.INDEX_CONSTRAINT_EQ && cst.Usable {
    31  			idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
    32  				Omit:      true,
    33  				ArgvIndex: 1,
    34  			}
    35  			idx.EstimatedCost = 1
    36  			idx.EstimatedRows = 100
    37  			return nil
    38  		}
    39  	}
    40  	return sqlite3.CONSTRAINT
    41  }
    42  
    43  func (array) Open() (sqlite3.VTabCursor, error) {
    44  	return &cursor{}, nil
    45  }
    46  
    47  type cursor struct {
    48  	array reflect.Value
    49  	rowID int
    50  }
    51  
    52  func (c *cursor) EOF() bool {
    53  	return c.rowID >= c.array.Len()
    54  }
    55  
    56  func (c *cursor) Next() error {
    57  	c.rowID++
    58  	return nil
    59  }
    60  
    61  func (c *cursor) RowID() (int64, error) {
    62  	return int64(c.rowID), nil
    63  }
    64  
    65  func (c *cursor) Column(ctx *sqlite3.Context, n int) error {
    66  	if n != 0 {
    67  		return nil
    68  	}
    69  
    70  	v := c.array.Index(c.rowID)
    71  	k := v.Kind()
    72  
    73  	if k == reflect.Interface {
    74  		if v.IsNil() {
    75  			ctx.ResultNull()
    76  			return nil
    77  		}
    78  		v = v.Elem()
    79  		k = v.Kind()
    80  	}
    81  
    82  	switch {
    83  	case v.CanInt():
    84  		ctx.ResultInt64(v.Int())
    85  
    86  	case v.CanUint():
    87  		i64 := int64(v.Uint())
    88  		if i64 < 0 {
    89  			return fmt.Errorf("array: integer element overflow:%.0w %d", sqlite3.MISMATCH, v.Uint())
    90  		}
    91  		ctx.ResultInt64(i64)
    92  
    93  	case v.CanFloat():
    94  		ctx.ResultFloat(v.Float())
    95  
    96  	case k == reflect.Bool:
    97  		ctx.ResultBool(v.Bool())
    98  
    99  	case k == reflect.String:
   100  		ctx.ResultText(v.String())
   101  
   102  	case (k == reflect.Slice || k == reflect.Array && v.CanAddr()) &&
   103  		v.Type().Elem().Kind() == reflect.Uint8:
   104  		ctx.ResultBlob(v.Bytes())
   105  
   106  	default:
   107  		return fmt.Errorf("array: unsupported element:%.0w %v", sqlite3.MISMATCH, util.ReflectType(v))
   108  	}
   109  	return nil
   110  }
   111  
   112  func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
   113  	array := reflect.ValueOf(arg[0].Pointer())
   114  	array, err := indexable(array)
   115  	if err != nil {
   116  		return err
   117  	}
   118  
   119  	c.array = array
   120  	c.rowID = 0
   121  	return nil
   122  }
   123  
   124  func indexable(v reflect.Value) (reflect.Value, error) {
   125  	switch v.Kind() {
   126  	case reflect.Slice:
   127  		return v, nil
   128  	case reflect.Array:
   129  		return v, nil
   130  	case reflect.Pointer:
   131  		if v := v.Elem(); v.Kind() == reflect.Array {
   132  			return v, nil
   133  		}
   134  	}
   135  	return v, fmt.Errorf("array: unsupported argument:%.0w %v", sqlite3.MISMATCH, util.ReflectType(v))
   136  }