good morning!!!!

Skip to content
Snippets Groups Projects
query.go 2.16 KiB
Newer Older
Garet Halliday's avatar
Garet Halliday committed
package psql

import (
Garet Halliday's avatar
a  
Garet Halliday committed
	"reflect"
Garet Halliday's avatar
Garet Halliday committed
	"strconv"
Garet Halliday's avatar
Garet Halliday committed

	"pggat2/lib/bouncer/backends/v0"
Garet Halliday's avatar
Garet Halliday committed
	"pggat2/lib/fed"
	packets "pggat2/lib/fed/packets/v3.0"
Garet Halliday's avatar
Garet Halliday committed
func Query(server fed.ReadWriter, result any, query string, args ...any) error {
Garet Halliday's avatar
Garet Halliday committed
	res := reflect.ValueOf(result)

Garet Halliday's avatar
Garet Halliday committed
	if len(args) == 0 {
		// simple query

		w := resultWriter{
Garet Halliday's avatar
Garet Halliday committed
			result: res,
Garet Halliday's avatar
Garet Halliday committed
		}
		ctx := backends.Context{
Garet Halliday's avatar
Garet Halliday committed
			Peer: fed.CombinedReadWriter{
Garet Halliday's avatar
Garet Halliday committed
				Reader: eofReader{},
				Writer: &w,
			},
		}
		if err := backends.QueryString(&ctx, server, query); err != nil {
			return err
		}
		if w.err != nil {
			return w.err
		}

		return nil
	}

	// must use eqp

	// parse
	parse := packets.Parse{
		Query: query,
	}

	// bind
	params := make([][]byte, 0, len(args))
Garet Halliday's avatar
Garet Halliday committed
outer:
Garet Halliday's avatar
Garet Halliday committed
	for _, arg := range args {
		var value []byte
Garet Halliday's avatar
Garet Halliday committed
		argr := reflect.ValueOf(arg)
		for argr.Kind() == reflect.Pointer {
			if argr.IsNil() {
				params = append(params, nil)
				continue outer
			}
			argr = argr.Elem()
		}
		switch argr.Kind() {
		case reflect.String:
			value = []byte(argr.String())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			value = []byte(strconv.FormatUint(argr.Uint(), 10))
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			value = []byte(strconv.FormatInt(argr.Int(), 10))
		case reflect.Float32, reflect.Float64:
			value = []byte(strconv.FormatFloat(argr.Float(), 'f', -1, 64))
		case reflect.Bool:
			if argr.Bool() {
				value = []byte{'t'}
			} else {
				value = []byte{'f'}
			}
Garet Halliday's avatar
Garet Halliday committed
		default:
			return ErrUnexpectedType
		}
		params = append(params, value)
	}
	bind := packets.Bind{
		ParameterValues: params,
	}

	// describe
	describe := packets.Describe{
		Which: 'P',
	}

	// execute
Garet Halliday's avatar
Garet Halliday committed
	execute := packets.Execute{}
Garet Halliday's avatar
Garet Halliday committed
	// sync
Garet Halliday's avatar
Garet Halliday committed
	sync := fed.NewPacket(packets.TypeSync)
Garet Halliday's avatar
Garet Halliday committed
	w := resultWriter{
Garet Halliday's avatar
Garet Halliday committed
		result: res,
Garet Halliday's avatar
a  
Garet Halliday committed
	}
Garet Halliday's avatar
Garet Halliday committed
	r := packetReader{
Garet Halliday's avatar
Garet Halliday committed
		packets: []fed.Packet{
Garet Halliday's avatar
Garet Halliday committed
			bind.IntoPacket(),
			describe.IntoPacket(),
			execute.IntoPacket(),
			sync,
		},
	}
Garet Halliday's avatar
Garet Halliday committed
	ctx := backends.Context{
Garet Halliday's avatar
Garet Halliday committed
		Peer: fed.CombinedReadWriter{
Garet Halliday's avatar
Garet Halliday committed
			Reader: &r,
			Writer: &w,
		},
Garet Halliday's avatar
Garet Halliday committed
	}
Garet Halliday's avatar
Garet Halliday committed

	if err := backends.Transaction(&ctx, server, parse.IntoPacket()); err != nil {
Garet Halliday's avatar
Garet Halliday committed
		return err
	}
Garet Halliday's avatar
Garet Halliday committed
	if w.err != nil {
		return w.err
	}
Garet Halliday's avatar
Garet Halliday committed

	return nil
}