Skip to content

Commit

Permalink
Merge pull request #423 from hmmftg/master
Browse files Browse the repository at this point in the history
hide DBOutput to decrease complexity
  • Loading branch information
sijms committed Aug 11, 2023
2 parents fe70d9d + 7ca0fce commit da41292
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 24 deletions.
76 changes: 70 additions & 6 deletions dbms/output.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,91 @@
package dbms

import (
"context"
"database/sql"
go_ora "github.com/sijms/go-ora/v2"
"fmt"
"io"

go_ora "github.com/sijms/go-ora/v2"
)

type DBOutput struct {
bufferSize int
conn *sql.DB
}

const (
MaxBufferSize = 0x7FFF
MinBufferSize = 2000
KeyInContext = "GO-ORA.DBMS_OUTPUT"
)

// enable oracle output for current session
// param:
//
// ctx: context of goroutine used in large apps
// for main: context.Background()
// for rest apis:
// http.Request.Context()
// gin.Context
// fiber.Ctx.Context()
// ...
func EnableOutput(ctx context.Context, conn *sql.DB) error {
out, err := NewOutput(conn, MaxBufferSize)
if err != nil {
return err
}
context.WithValue(ctx, KeyInContext, out)
return nil
}

// disable oracle output for current session
func DisableOutput(ctx context.Context) error {
out := ctx.Value(KeyInContext)
if out == nil {
return fmt.Errorf("invalid context")
}
err := out.(*DBOutput).Close()
if err != nil {
return err
}
return nil
}

// get oracle output for current session
func GetOutput(ctx context.Context) (string, error) {
out := ctx.Value(KeyInContext)
if out == nil {
return "", fmt.Errorf("invalid context")
}
output, err := out.(*DBOutput).GetOutput()
if err != nil {
return "", err
}
return output, nil
}

// print oracle output into StringWriter for current session
func PrintOutput(ctx context.Context, w io.StringWriter) error {
output, err := GetOutput(ctx)
if err != nil {
return err
}
_, err = w.WriteString(output)
return err
}

func NewOutput(conn *sql.DB, bufferSize int) (*DBOutput, error) {
output := &DBOutput{
bufferSize: bufferSize,
conn: conn,
}
sqlText := `begin dbms_output.enable(:1); end;`
if output.bufferSize > 0x7FFF {
output.bufferSize = 0x7FFF
if output.bufferSize > MaxBufferSize {
output.bufferSize = MaxBufferSize
}
if output.bufferSize < 2000 {
output.bufferSize = 2000
if output.bufferSize < MinBufferSize {
output.bufferSize = MinBufferSize
}
_, err := output.conn.Exec(sqlText, bufferSize)
return output, err
Expand Down Expand Up @@ -55,7 +119,7 @@ end;`
state int
output string
)
_, err := db_out.conn.Exec(sqlText, 0x7FFF, go_ora.Out{Dest: &state},
_, err := db_out.conn.Exec(sqlText, MaxBufferSize, go_ora.Out{Dest: &state},
go_ora.Out{Dest: &output, Size: db_out.bufferSize})
return output, err
}
Expand Down
84 changes: 66 additions & 18 deletions examples/dbms_output/main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package main

import (
"context"
"database/sql"
"fmt"
"os"

"github.com/sijms/go-ora/dbms"
_ "github.com/sijms/go-ora/v2"
"os"
)

func exec_simple_conn(conn *sql.DB, texts ...string) error {
Expand All @@ -18,53 +20,99 @@ func exec_simple_conn(conn *sql.DB, texts ...string) error {
}
return err
}
func main() {
conn, err := sql.Open("oracle", os.Getenv("DSN"))

func addOutput(conn *sql.DB, data string) error {
return exec_simple_conn(conn, fmt.Sprintf(`--sql
BEGIN
DBMS_OUTPUT.PUT_LINE('%s');
END;
`, data))
}

func withoutContext(conn *sql.DB) {
output, err := dbms.NewOutput(conn, 0x7FFF)
if err != nil {
fmt.Println("error in connection: ", err)
fmt.Println("can't init DBMS_OUTPUT: ", err)
return
}
defer func() {
err = conn.Close()
err = output.Close()
if err != nil {
fmt.Println("error in close: ", err)
fmt.Println("can't end dbms_output: ", err)
}
}()
output, err := dbms.NewOutput(conn, 0x7FFF)
err = addOutput(conn, "test1")
if err != nil {
fmt.Println("can't write output: ", err)
return
}
line, err := output.GetOutput()
if err != nil {
fmt.Println("can't get output: ", err)
return
}
fmt.Print(line)
err = addOutput(conn, "test2")
if err != nil {
fmt.Println("can't write output: ", err)
return
}
err = output.Print(os.Stdout)
if err != nil {
fmt.Println("can't print: ", err)
return
}
}

func withContext(conn *sql.DB, ctx context.Context) {
err := dbms.EnableOutput(ctx, conn)
if err != nil {
fmt.Println("can't init DBMS_OUTPUT: ", err)
return
}
defer func() {
err = output.Close()
err = dbms.DisableOutput(ctx)
if err != nil {
fmt.Println("can't end dbms_output: ", err)
}
}()
err = exec_simple_conn(conn, `BEGIN
DBMS_OUTPUT.PUT_LINE('this is a test');
END;`)
err = addOutput(conn, "test1")
if err != nil {
fmt.Println("can't write output: ", err)
return
}
line, err := output.GetOutput()
output, err := dbms.GetOutput(ctx)
if err != nil {
fmt.Println("can't get output: ", err)
return
}
fmt.Print(line)
err = exec_simple_conn(conn, `BEGIN
DBMS_OUTPUT.PUT_LINE('this is a test2');
END;`)
fmt.Print(output)
err = addOutput(conn, "test2")
if err != nil {
fmt.Println("can't write output: ", err)
return
}
err = output.Print(os.Stdout)
err = dbms.PrintOutput(ctx, os.Stdout)
if err != nil {
fmt.Println("can't print: ", err)
fmt.Println("can't print output: ", err)
return
}
}

func main() {
conn, err := sql.Open("oracle", os.Getenv("DSN"))
if err != nil {
fmt.Println("error in connection: ", err)
return
}
defer func() {
err = conn.Close()
if err != nil {
fmt.Println("error in close: ", err)
}
}()

withoutContext(conn)
ctx := context.Background()
withContext(conn, ctx)
}

0 comments on commit da41292

Please sign in to comment.