Skip to content
Snippets Groups Projects
Unverified Commit 6b04d706 authored by tjie's avatar tjie Committed by GitHub
Browse files

Add built-in function oct (#2115) (#2402)


* Add built-in function oct (#2115)

Signed-off-by: default avatarlawrshen <191220090@smail.nju.edu.cn>

* refine: use bit operations instead of strconv.FormatUint

Signed-off-by: default avatarlawrshen <191220090@smail.nju.edu.cn>
parent 406c7c8f
No related branches found
No related tags found
No related merge requests found
......@@ -23,6 +23,7 @@ const (
Substring
Ltrim
Rtrim
Oct
StartsWith
Lpad
Rpad
......
// Copyright 2022 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package unary
import (
"fmt"
"github.com/matrixorigin/matrixone/pkg/builtin"
"github.com/matrixorigin/matrixone/pkg/container/nulls"
"github.com/matrixorigin/matrixone/pkg/container/types"
"github.com/matrixorigin/matrixone/pkg/container/vector"
"github.com/matrixorigin/matrixone/pkg/sql/colexec/extend"
"github.com/matrixorigin/matrixone/pkg/sql/colexec/extend/overload"
"github.com/matrixorigin/matrixone/pkg/vectorize/oct"
"github.com/matrixorigin/matrixone/pkg/vm/process"
)
var OctArgAndRets = []argsAndRet{
{[]types.T{types.T_uint8}, types.T_char},
{[]types.T{types.T_uint8}, types.T_varchar},
{[]types.T{types.T_uint16}, types.T_char},
{[]types.T{types.T_uint16}, types.T_varchar},
{[]types.T{types.T_uint32}, types.T_char},
{[]types.T{types.T_uint32}, types.T_varchar},
{[]types.T{types.T_uint64}, types.T_char},
{[]types.T{types.T_uint64}, types.T_varchar},
{[]types.T{types.T_int8}, types.T_char},
{[]types.T{types.T_int8}, types.T_varchar},
{[]types.T{types.T_int16}, types.T_char},
{[]types.T{types.T_int16}, types.T_varchar},
{[]types.T{types.T_int32}, types.T_char},
{[]types.T{types.T_int32}, types.T_varchar},
{[]types.T{types.T_int64}, types.T_char},
{[]types.T{types.T_int64}, types.T_varchar},
}
func init() {
extend.FunctionRegistry["oct"] = builtin.Oct
// register function args and returns
for _, argAndRet := range OctArgAndRets {
overload.AppendFunctionRets(builtin.Oct, argAndRet.args, argAndRet.ret)
}
extend.UnaryReturnTypes[builtin.Oct] = func(extend extend.Extend) types.T {
return getUnaryReturnType(builtin.Oct, extend)
}
extend.UnaryStrings[builtin.Oct] = func(extend extend.Extend) string {
return fmt.Sprintf("oct(%s)", extend)
}
overload.OpTypes[builtin.Oct] = overload.Unary
// prepare for function call
overload.UnaryOps[builtin.Oct] = []*overload.UnaryOp{
{ // T_uint8 to T_char
Typ: types.T_uint8,
ReturnType: types.T_char,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]uint8)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctUint8(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_char, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_uint8 to T_varchar
Typ: types.T_uint8,
ReturnType: types.T_varchar,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]uint8)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctUint8(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_varchar, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_uint16 to T_char
Typ: types.T_uint16,
ReturnType: types.T_char,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]uint16)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctUint16(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_char, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_uint16 to T_varchar
Typ: types.T_uint16,
ReturnType: types.T_varchar,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]uint16)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctUint16(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_varchar, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_uint32 to T_char
Typ: types.T_uint32,
ReturnType: types.T_char,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]uint32)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctUint32(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_char, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_uint32 to T_varchar
Typ: types.T_uint32,
ReturnType: types.T_varchar,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]uint32)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctUint32(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_varchar, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_uint64 to T_char
Typ: types.T_uint64,
ReturnType: types.T_char,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]uint64)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctUint64(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_char, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_uint64 to T_varchar
Typ: types.T_uint64,
ReturnType: types.T_varchar,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]uint64)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctUint64(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_varchar, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_int8 to T_char
Typ: types.T_int8,
ReturnType: types.T_char,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]int8)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctInt8(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_char, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_int8 to T_varchar
Typ: types.T_int8,
ReturnType: types.T_varchar,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]int8)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctInt8(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_varchar, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_int16 to T_char
Typ: types.T_int16,
ReturnType: types.T_char,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]int16)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctInt16(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_char, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_int16 to T_varchar
Typ: types.T_int16,
ReturnType: types.T_varchar,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]int16)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctInt16(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_varchar, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_int32 to T_char
Typ: types.T_int32,
ReturnType: types.T_char,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]int32)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctInt32(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_char, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_int32 to T_varchar
Typ: types.T_int32,
ReturnType: types.T_varchar,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]int32)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctInt32(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_varchar, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_int64 to T_char
Typ: types.T_int64,
ReturnType: types.T_char,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]int64)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctInt64(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_char, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
{ // T_int64 to T_varchar
Typ: types.T_int64,
ReturnType: types.T_varchar,
Fn: func(origVec *vector.Vector, proc *process.Process, _ bool) (*vector.Vector, error) {
col := origVec.Col.([]int64)
results := &types.Bytes{
Data: []byte{},
Offsets: make([]uint32, len(col)),
Lengths: make([]uint32, len(col)),
}
results = oct.OctInt64(col, results)
resVec, err := process.Get(proc, int64(len(results.Data)), types.Type{Oid: types.T_varchar, Size: 24})
if err != nil {
return nil, err
}
nulls.Set(resVec.Nsp, origVec.Nsp)
vector.SetCol(resVec, results)
return resVec, nil
},
},
}
}
// Copyright 2022 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package oct
import (
"github.com/matrixorigin/matrixone/pkg/container/types"
"golang.org/x/exp/constraints"
)
var (
OctUint8 func([]uint8, *types.Bytes) *types.Bytes
OctUint16 func([]uint16, *types.Bytes) *types.Bytes
OctUint32 func([]uint32, *types.Bytes) *types.Bytes
OctUint64 func([]uint64, *types.Bytes) *types.Bytes
OctInt8 func([]int8, *types.Bytes) *types.Bytes
OctInt16 func([]int16, *types.Bytes) *types.Bytes
OctInt32 func([]int32, *types.Bytes) *types.Bytes
OctInt64 func([]int64, *types.Bytes) *types.Bytes
)
func init() {
OctUint8 = oct[uint8]
OctUint16 = oct[uint16]
OctUint32 = oct[uint32]
OctUint64 = oct[uint64]
OctInt8 = oct[int8]
OctInt16 = oct[int16]
OctInt32 = oct[int32]
OctInt64 = oct[int64]
}
func oct[T constraints.Unsigned | constraints.Signed](xs []T, rs *types.Bytes) *types.Bytes {
var cursor uint32
for idx := range xs {
octbytes := uint64ToOctonary(uint64(xs[idx]))
for i := range octbytes {
rs.Data = append(rs.Data, octbytes[i])
}
rs.Offsets[idx] = cursor
rs.Lengths[idx] = uint32(len(octbytes))
cursor += uint32(len(octbytes))
}
return rs
}
func uint64ToOctonary(x uint64) []byte {
var a [21 + 1]byte // 64bit value in base 8 [64/3+(64%3!=0)]
i := len(a)
// Use shifts and masks instead of / and %.
for x >= 8 {
i--
a[i] = byte(x&7 + '0')
x >>= 3
}
// x < 8
i--
a[i] = byte(x + '0')
return a[i:]
}
// Copyright 2022 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package oct
import (
"testing"
"github.com/matrixorigin/matrixone/pkg/container/types"
"github.com/stretchr/testify/require"
)
func TestOctUint8(t *testing.T) {
args := []uint8{12, 99, 100, 255}
want := &types.Bytes{
Data: []byte("14143144377"),
Lengths: []uint32{2, 3, 3, 3},
Offsets: []uint32{0, 2, 5, 8},
}
out := &types.Bytes{
Data: []byte{},
Lengths: make([]uint32, len(args)),
Offsets: make([]uint32, len(args)),
}
out = OctUint8(args, out)
require.Equal(t, want, out)
}
func TestOctUint16(t *testing.T) {
args := []uint16{12, 99, 100, 255, 1024, 10000, 65535}
want := &types.Bytes{
Data: []byte("14143144377200023420177777"),
Lengths: []uint32{2, 3, 3, 3, 4, 5, 6},
Offsets: []uint32{0, 2, 5, 8, 11, 15, 20},
}
out := &types.Bytes{
Data: []byte{},
Lengths: make([]uint32, len(args)),
Offsets: make([]uint32, len(args)),
}
out = OctUint16(args, out)
require.Equal(t, want, out)
}
func TestOctUint32(t *testing.T) {
args := []uint32{12, 99, 100, 255, 1024, 10000, 65535, 4294967295}
want := &types.Bytes{
Data: []byte("1414314437720002342017777737777777777"),
Lengths: []uint32{2, 3, 3, 3, 4, 5, 6, 11},
Offsets: []uint32{0, 2, 5, 8, 11, 15, 20, 26},
}
out := &types.Bytes{
Data: []byte{},
Lengths: make([]uint32, len(args)),
Offsets: make([]uint32, len(args)),
}
out = OctUint32(args, out)
require.Equal(t, want, out)
}
func TestOctUint64(t *testing.T) {
args := []uint64{12, 99, 100, 255, 1024, 10000, 65535, 4294967295, 18446744073709551615}
want := &types.Bytes{
Data: []byte("14143144377200023420177777377777777771777777777777777777777"),
Lengths: []uint32{2, 3, 3, 3, 4, 5, 6, 11, 22},
Offsets: []uint32{0, 2, 5, 8, 11, 15, 20, 26, 37},
}
out := &types.Bytes{
Data: []byte{},
Lengths: make([]uint32, len(args)),
Offsets: make([]uint32, len(args)),
}
out = OctUint64(args, out)
require.Equal(t, want, out)
}
func TestOctInt8(t *testing.T) {
args := []int8{-128, -1, 127}
want := &types.Bytes{
Data: []byte("17777777777777777776001777777777777777777777177"),
Lengths: []uint32{22, 22, 3},
Offsets: []uint32{0, 22, 44},
}
out := &types.Bytes{
Data: []byte{},
Lengths: make([]uint32, len(args)),
Offsets: make([]uint32, len(args)),
}
out = OctInt8(args, out)
require.Equal(t, want, out)
}
func TestOctInt16(t *testing.T) {
args := []int16{-32768}
want := &types.Bytes{
Data: []byte("1777777777777777700000"),
Lengths: []uint32{22},
Offsets: []uint32{0},
}
out := &types.Bytes{
Data: []byte{},
Lengths: make([]uint32, len(args)),
Offsets: make([]uint32, len(args)),
}
out = OctInt16(args, out)
require.Equal(t, want, out)
}
func TestOctInt32(t *testing.T) {
args := []int32{-2147483648}
want := &types.Bytes{
Data: []byte("1777777777760000000000"),
Lengths: []uint32{22},
Offsets: []uint32{0},
}
out := &types.Bytes{
Data: []byte{},
Lengths: make([]uint32, len(args)),
Offsets: make([]uint32, len(args)),
}
out = OctInt32(args, out)
require.Equal(t, want, out)
}
func TestOctInt64(t *testing.T) {
args := []int64{-9223372036854775808}
want := &types.Bytes{
Data: []byte("1000000000000000000000"),
Lengths: []uint32{22},
Offsets: []uint32{0},
}
out := &types.Bytes{
Data: []byte{},
Lengths: make([]uint32, len(args)),
Offsets: make([]uint32, len(args)),
}
out = OctInt64(args, out)
require.Equal(t, want, out)
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment