Skip to content

Commit

Permalink
Add support for protocol v3 and add QuerySQL and ExecuteSQL clien…
Browse files Browse the repository at this point in the history
…t methods (#328)
  • Loading branch information
jaclarke authored Jan 14, 2025
1 parent 9af85f6 commit 2daf9b2
Show file tree
Hide file tree
Showing 23 changed files with 500 additions and 8 deletions.
4 changes: 4 additions & 0 deletions errors_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const (
UnknownUserError = edgedb.UnknownUserError
UnknownDatabaseError = edgedb.UnknownDatabaseError
UnknownParameterError = edgedb.UnknownParameterError
DeprecatedScopingError = edgedb.DeprecatedScopingError
SchemaError = edgedb.SchemaError
SchemaDefinitionError = edgedb.SchemaDefinitionError
InvalidDefinitionError = edgedb.InvalidDefinitionError
Expand Down Expand Up @@ -102,6 +103,9 @@ const (
AuthenticationError = edgedb.AuthenticationError
AvailabilityError = edgedb.AvailabilityError
BackendUnavailableError = edgedb.BackendUnavailableError
ServerOfflineError = edgedb.ServerOfflineError
UnknownTenantError = edgedb.UnknownTenantError
ServerBlockedError = edgedb.ServerBlockedError
BackendError = edgedb.BackendError
UnsupportedBackendFeatureError = edgedb.UnsupportedBackendFeatureError
ClientError = edgedb.ClientError
Expand Down
2 changes: 2 additions & 0 deletions internal/client/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type idPair struct {
}

type queryKey struct {
lang Language
cmd string
fmt Format
expCard Cardinality
Expand All @@ -76,6 +77,7 @@ type queryKey struct {

func makeKey(q *query) queryKey {
return queryKey{
lang: q.lang,
cmd: q.cmd,
fmt: q.fmt,
expCard: q.expCard,
Expand Down
46 changes: 46 additions & 0 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,52 @@ func (p *Client) QuerySingleJSON(
return firstError(err, p.release(conn, err))
}

// QuerySQL runs a SQL query and returns the results.
func (p *Client) QuerySQL(
ctx context.Context,
cmd string,
out interface{},
args ...interface{},
) error {
conn, err := p.acquire(ctx)
if err != nil {
return err
}

err = runQuery(
ctx, conn, "QuerySQL", cmd, out, args, p.state, p.warningHandler)
return firstError(err, p.release(conn, err))
}

// ExecuteSQL executes a SQL command (or commands).
func (p *Client) ExecuteSQL(
ctx context.Context,
cmd string,
args ...interface{},
) error {
conn, err := p.acquire(ctx)
if err != nil {
return err
}

q, err := newQuery(
"ExecuteSQL",
cmd,
args,
conn.capabilities1pX(),
copyState(p.state),
nil,
true,
p.warningHandler,
)
if err != nil {
return err
}

err = conn.scriptFlow(ctx, q)
return firstError(err, p.release(conn, err))
}

// Tx runs an action in a transaction retrying failed actions
// if they might succeed on a subsequent attempt.
//
Expand Down
58 changes: 58 additions & 0 deletions internal/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,64 @@ func TestQuerySingleJSONMissingResult(t *testing.T) {
"the \"out\" argument must be *[]byte or *OptionalBytes, got *string")
}

func TestQuerySQL(t *testing.T) {
ctx := context.Background()

var version int64
err := client.QuerySingle(ctx, "SELECT sys::get_version().major", &version)
assert.NoError(t, err)

if version >= 6 {
err = client.ExecuteSQL(ctx, "select 1")
assert.NoError(t, err)

var result []struct {
Col1 int32 `edgedb:"col~1"`
}
err = client.QuerySQL(ctx, "select 1", &result)
assert.NoError(t, err)
assert.Equal(t, int32(1), result[0].Col1)

type res2 struct {
Foo int32 `edgedb:"foo"`
Bar int32 `edgedb:"bar"`
}
var result2 []res2
err = client.QuerySQL(ctx, "select 1 AS foo, 2 AS bar", &result2)
assert.NoError(t, err)
assert.Equal(t, []res2{
{
Foo: 1,
Bar: 2,
},
}, result2)

var result3 []struct {
Col1 int64 `edgedb:"col~1"`
}
err = client.QuerySQL(ctx, "select 1 + $1::int8", &result3, int64(41))
assert.NoError(t, err)
assert.Equal(t, int64(42), result3[0].Col1)
} else {
var res []interface{}
err = client.QuerySQL(ctx, "select 1", &res)
assert.EqualError(
t, err,
"edgedb.UnsupportedFeatureError: "+
"the server does not support SQL queries, "+
"upgrade to 6.0 or newer",
)

err = client.ExecuteSQL(ctx, "select 1")
assert.EqualError(
t, err,
"edgedb.UnsupportedFeatureError: "+
"the server does not support SQL queries, "+
"upgrade to 6.0 or newer",
)
}
}

// TODO: return when session_idle_timeout changes
// will be reflected at connection creation

Expand Down
3 changes: 2 additions & 1 deletion internal/client/connutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ var (
`^(\w(?:-?\w)*)$`,
)
cloudInstanceNameRe = regexp.MustCompile(
`^([A-Za-z0-9_\-](?:-?[A-Za-z_0-9\-])*)/([A-Za-z0-9](?:-?[A-Za-z0-9])*)$`,
`^([A-Za-z0-9_\-](?:-?[A-Za-z_0-9\-])*)/` +
`([A-Za-z0-9](?:-?[A-Za-z0-9])*)$`,
)
domainLabelMaxLength = 63
crcTable *crc16.Table = crc16.MakeTable(crc16.CRC16_XMODEM)
Expand Down
3 changes: 2 additions & 1 deletion internal/client/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ var (
defaultConcurrency = max(4, runtime.NumCPU())

protocolVersionMin = protocolVersion0p13
protocolVersionMax = protocolVersion2p0
protocolVersionMax = protocolVersion3p0
protocolVersion0p13 = internal.ProtocolVersion{Major: 0, Minor: 13}
protocolVersion1p0 = internal.ProtocolVersion{Major: 1, Minor: 0}
protocolVersion2p0 = internal.ProtocolVersion{Major: 2, Minor: 0}
protocolVersion3p0 = internal.ProtocolVersion{Major: 3, Minor: 0}

capabilitiesSessionConfig uint64 = 0x2
capabilitiesTransaction uint64 = 0x4
Expand Down
14 changes: 14 additions & 0 deletions internal/client/edgedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ func (c *protocolConnection) isClosed() bool {
}

func (c *protocolConnection) scriptFlow(ctx context.Context, q *query) error {
if q.lang == SQL && c.protocolVersion.LT(protocolVersion3p0) {
return &unsupportedFeatureError{
msg: "the server does not support SQL queries, " +
"upgrade to 6.0 or newer",
}
}

r, err := c.acquireReader(ctx)
if err != nil {
return err
Expand Down Expand Up @@ -210,6 +217,13 @@ func (c *protocolConnection) granularFlow(
ctx context.Context,
q *query,
) error {
if q.lang == SQL && c.protocolVersion.LT(protocolVersion3p0) {
return &unsupportedFeatureError{
msg: "the server does not support SQL queries, " +
"upgrade to 6.0 or newer",
}
}

r, err := c.acquireReader(ctx)
if err != nil {
return err
Expand Down
Loading

0 comments on commit 2daf9b2

Please sign in to comment.