Latest commit

History

1,718 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GoPkgGoDevGo Report Cardcodecov

Go DRiver for ORacle

godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper, ODPI-C.

Build-time Requirements

  • Go 1.15
  • C compiler with CGO_ENABLED=1 - so cross-compilation is hard

Run-time Requirements

  • Oracle Client libraries - see ODPI-C

Although Oracle Client libraries are NOT required for compiling, they are needed at run time. Download the free Basic or Basic Light package from https://www.oracle.com/database/technologies/instant-client/downloads.html.

Rationale

With Go 1.9, driver-specific things are not needed, everything (I need) can be achieved with the standard database/sql library. Even calling stored procedures with OUT parameters, or sending/retrieving PL/SQL array types - just give a godror.PlSQLArrays Option within the parameters of Exec (but not in sql.Named)! For example, the array size of the returned PL/SQL arrays can be set with godror.ArraySize(2000) (default value is 1024).

Documentation

See Godror API Documentation and the Godror User Guide.

Installation

Run:

go get github.com/godror/godror@latest

Then install Oracle Client libraries and you're ready to go!

godror is cgo package. If you want to build your app using godror, you need gcc (a C compiler).

Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compile present within your path.

See Godror Installation for more information.

Connection

To connect to Oracle Database use sql.Open("godror", dataSourceName), where dataSourceName is a logfmt-encoded parameter list. Specify at least "user", "password" and "connectString". For example:

db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)

The connectString can be ANYTHING that SQL*Plus or Oracle Call Interface (OCI) accepts: a service name, an Easy Connect string like host:port/service_name, or a connect descriptor like (DESCRIPTION=...).

You can specify connection timeout seconds with "?connect_timeout=15" - Ping uses this timeout, NOT the Deadline in Context! Note that connect_timeout requires at least 19c client.

For more connection options, see Godor Connection Handling.

Extras

To use the godror-specific functions, you'll need a *godror.conn. That's what godror.DriverConn is for! See z_qrcn_test.go for using that to reach NewSubscription.

Calling stored procedures

Use ExecContext and mark each OUT parameter with sql.Out.

As sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR), you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Lob/Rows.

Using cursors returned by stored procedures

Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.

As sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Rows.

For examples, see Anthony Tuininga's presentation about Go (page 41)!

Caveats

sql.NullString

sql.NullString is not supported: Oracle DB does not differentiate between an empty string ("") and a NULL, so an

sql.NullString{String:"", Valid:true} == sql.NullString{String:"", Valid:false}

and this would be more confusing than not supporting sql.NullString at all.

Just use plain old string !

NUMBER

NUMBERs are transferred as string to Go under the hood. This ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits), and sql.Scan will hide this and Scan into your int64, float64 or string, as you wish.

For PLS_INTEGER and BINARY_INTEGER (PL/SQL data types) you can use int32.

CLOB, BLOB

From 2.9.0, LOBs are returned as string/[]byte by default (before it needed the ClobAsString() option). Now it's reversed, and the default is string, to get a Lob reader, give the LobAsReader() option.

Watch out, Oracle will error out if the CLOB is too large, and you have to use godror.Lob in such cases!

If you return Lob as a reader, watch out with sql.QueryRow, sql.QueryRowContext ! They close the statement right after you Scan from the returned *Row, the returned Lob will be invalid, producing getSize: ORA-00000: DPI-1002: invalid dpiLob handle.

So, use a separate Stmt or sql.QueryContext.

For writing a LOB, the LOB locator returned from the database is valid only till the Stmt is valid! So Prepare the statement for the retrieval, then Exec, and only Close the stmt iff you've finished with your LOB! For example, see z_lob_test.go, TestLOBAppend.

TIMESTAMP

As I couldn't make TIMESTAMP arrays work, all time.Time is bind as DATE, so fractional seconds are lost. A workaround is converting to string:

time.Now().Format("2-Jan-06 3:04:05.000000 PM")

See #121 under the old project.

Timezone

See the documentation - but for short, the database's OS' time zone is used, as that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently), then set the "location" in the connection string, or the Timezone in the ConnectionParams accord to your chosen timezone.

Stored procedure returning cursor (result set)

varrset1, rset2 driver.Rowsconstquery=`BEGIN Package.StoredProcA(123, :1, :2); END;`stmt, err:=db.PrepareContext(ctx, query)
iferr!=nil {
returnfmt.Errorf("%s: %w", query, err)
}
deferstmt.Close()
if_, err:=stmt.ExecContext(ctx, sql.Out{Dest: &rset1}, sql.Out{Dest: &rset2}); err!=nil {
log.Printf("Error running %q: %+v", query, err)
return
}
deferrset1.Close()
deferrset2.Close()
cols1:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests1:=make([]driver.Value, len(cols1))
for {
iferr:=rset1.Next(dests1); err!=nil {
iferr==io.EOF {
break
}
rset1.Close()
returnerr
}
fmt.Println(dests1)
}
cols2:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests2:=make([]driver.Value, len(cols2))
for {
iferr:=rset2.Next(dests2); err!=nil {
iferr==io.EOF {
break
}
rset2.Close()
returnerr
}
fmt.Println(dests2)
}

Context with Deadline/Timeout

TL;DR; *always close sql.Rows ASAP!

Creating a watchdog goroutine, done channel for each call of rows.Next kills performance, so we create only one watchdog goroutine, at the first rows.Next call. It is defused after rows.Close (or the cursor is exhausted).

If it is not defused, it will Break the currently executing OCI call on the connection, when the Context is canceled/timeouted. You should always call rows.Close ASAP, but if you experience random Breaks, remember this warning!

Contribute

Just as with other Go projects, you don't want to change the import paths, but you can hack on the library in place, just set up different remotes:

cd$GOPATH/src/github.com/godror/godror
git remote add upstream https://github.com/godror/godror.git
git fetch upstream
git checkout -b master upstream/master
git checkout -f master
git pull upstream master
git remote add fork git@github.com:mygithubacc/godror
git checkout -b newfeature upstream/master

Change, experiment as you wish. Then run

git commit -m 'my great changes'*.go
git push fork newfeature

and you're ready to send a GitHub Pull Request from the github.com/mygithubacc/godror branch called newfeature.

Pre-commit

Download a staticcheckrelease and add this to .git/hooks/pre-commit:

#!/bin/shset -e
output="$(gofmt -l "$@")"if [ -n"$output" ];thenecho>&2"Go files must be formatted with gofmt. Please run:"forfin$output;doecho>&2" gofmt -w $PWD/$f"doneexit 1
fi
go run ./check
exec staticcheck

Guidelines

As ODPI stores the error buffer in a thread-local-storage, we must ensure that the error is retrieved on the same thread as the prvious function executed on.

This means we have to encapsulate each execute-then-retrieve-error sequence in runtime.LockOSThread() and runtime.UnlockOSThread(). For details, see #120.

This is automatically detected by go run ./check which should be called in the pre-commit hook.

Third-party

  • oracall generates a server for calling stored procedures.

About

GO DRiver for ORacle DB

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

1,718 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GoPkgGoDevGo Report Cardcodecov

Go DRiver for ORacle

godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper, ODPI-C.

Build-time Requirements

  • Go 1.15
  • C compiler with CGO_ENABLED=1 - so cross-compilation is hard

Run-time Requirements

  • Oracle Client libraries - see ODPI-C

Although Oracle Client libraries are NOT required for compiling, they are needed at run time. Download the free Basic or Basic Light package from https://www.oracle.com/database/technologies/instant-client/downloads.html.

Rationale

With Go 1.9, driver-specific things are not needed, everything (I need) can be achieved with the standard database/sql library. Even calling stored procedures with OUT parameters, or sending/retrieving PL/SQL array types - just give a godror.PlSQLArrays Option within the parameters of Exec (but not in sql.Named)! For example, the array size of the returned PL/SQL arrays can be set with godror.ArraySize(2000) (default value is 1024).

Documentation

See Godror API Documentation and the Godror User Guide.

Installation

Run:

go get github.com/godror/godror@latest

Then install Oracle Client libraries and you're ready to go!

godror is cgo package. If you want to build your app using godror, you need gcc (a C compiler).

Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compile present within your path.

See Godror Installation for more information.

Connection

To connect to Oracle Database use sql.Open("godror", dataSourceName), where dataSourceName is a logfmt-encoded parameter list. Specify at least "user", "password" and "connectString". For example:

db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)

The connectString can be ANYTHING that SQL*Plus or Oracle Call Interface (OCI) accepts: a service name, an Easy Connect string like host:port/service_name, or a connect descriptor like (DESCRIPTION=...).

You can specify connection timeout seconds with "?connect_timeout=15" - Ping uses this timeout, NOT the Deadline in Context! Note that connect_timeout requires at least 19c client.

For more connection options, see Godor Connection Handling.

Extras

To use the godror-specific functions, you'll need a *godror.conn. That's what godror.DriverConn is for! See z_qrcn_test.go for using that to reach NewSubscription.

Calling stored procedures

Use ExecContext and mark each OUT parameter with sql.Out.

As sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR), you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Lob/Rows.

Using cursors returned by stored procedures

Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.

As sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Rows.

For examples, see Anthony Tuininga's presentation about Go (page 41)!

Caveats

sql.NullString

sql.NullString is not supported: Oracle DB does not differentiate between an empty string ("") and a NULL, so an

sql.NullString{String:"", Valid:true} == sql.NullString{String:"", Valid:false}

and this would be more confusing than not supporting sql.NullString at all.

Just use plain old string !

NUMBER

NUMBERs are transferred as string to Go under the hood. This ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits), and sql.Scan will hide this and Scan into your int64, float64 or string, as you wish.

For PLS_INTEGER and BINARY_INTEGER (PL/SQL data types) you can use int32.

CLOB, BLOB

From 2.9.0, LOBs are returned as string/[]byte by default (before it needed the ClobAsString() option). Now it's reversed, and the default is string, to get a Lob reader, give the LobAsReader() option.

Watch out, Oracle will error out if the CLOB is too large, and you have to use godror.Lob in such cases!

If you return Lob as a reader, watch out with sql.QueryRow, sql.QueryRowContext ! They close the statement right after you Scan from the returned *Row, the returned Lob will be invalid, producing getSize: ORA-00000: DPI-1002: invalid dpiLob handle.

So, use a separate Stmt or sql.QueryContext.

For writing a LOB, the LOB locator returned from the database is valid only till the Stmt is valid! So Prepare the statement for the retrieval, then Exec, and only Close the stmt iff you've finished with your LOB! For example, see z_lob_test.go, TestLOBAppend.

TIMESTAMP

As I couldn't make TIMESTAMP arrays work, all time.Time is bind as DATE, so fractional seconds are lost. A workaround is converting to string:

time.Now().Format("2-Jan-06 3:04:05.000000 PM")

See #121 under the old project.

Timezone

See the documentation - but for short, the database's OS' time zone is used, as that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently), then set the "location" in the connection string, or the Timezone in the ConnectionParams accord to your chosen timezone.

Stored procedure returning cursor (result set)

varrset1, rset2 driver.Rowsconstquery=`BEGIN Package.StoredProcA(123, :1, :2); END;`stmt, err:=db.PrepareContext(ctx, query)
iferr!=nil {
returnfmt.Errorf("%s: %w", query, err)
}
deferstmt.Close()
if_, err:=stmt.ExecContext(ctx, sql.Out{Dest: &rset1}, sql.Out{Dest: &rset2}); err!=nil {
log.Printf("Error running %q: %+v", query, err)
return
}
deferrset1.Close()
deferrset2.Close()
cols1:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests1:=make([]driver.Value, len(cols1))
for {
iferr:=rset1.Next(dests1); err!=nil {
iferr==io.EOF {
break
}
rset1.Close()
returnerr
}
fmt.Println(dests1)
}
cols2:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests2:=make([]driver.Value, len(cols2))
for {
iferr:=rset2.Next(dests2); err!=nil {
iferr==io.EOF {
break
}
rset2.Close()
returnerr
}
fmt.Println(dests2)
}

Context with Deadline/Timeout

TL;DR; *always close sql.Rows ASAP!

Creating a watchdog goroutine, done channel for each call of rows.Next kills performance, so we create only one watchdog goroutine, at the first rows.Next call. It is defused after rows.Close (or the cursor is exhausted).

If it is not defused, it will Break the currently executing OCI call on the connection, when the Context is canceled/timeouted. You should always call rows.Close ASAP, but if you experience random Breaks, remember this warning!

Contribute

Just as with other Go projects, you don't want to change the import paths, but you can hack on the library in place, just set up different remotes:

cd$GOPATH/src/github.com/godror/godror
git remote add upstream https://github.com/godror/godror.git
git fetch upstream
git checkout -b master upstream/master
git checkout -f master
git pull upstream master
git remote add fork git@github.com:mygithubacc/godror
git checkout -b newfeature upstream/master

Change, experiment as you wish. Then run

git commit -m 'my great changes'*.go
git push fork newfeature

and you're ready to send a GitHub Pull Request from the github.com/mygithubacc/godror branch called newfeature.

Pre-commit

Download a staticcheckrelease and add this to .git/hooks/pre-commit:

#!/bin/shset -e
output="$(gofmt -l "$@")"if [ -n"$output" ];thenecho>&2"Go files must be formatted with gofmt. Please run:"forfin$output;doecho>&2" gofmt -w $PWD/$f"doneexit 1
fi
go run ./check
exec staticcheck

Guidelines

As ODPI stores the error buffer in a thread-local-storage, we must ensure that the error is retrieved on the same thread as the prvious function executed on.

This means we have to encapsulate each execute-then-retrieve-error sequence in runtime.LockOSThread() and runtime.UnlockOSThread(). For details, see #120.

This is automatically detected by go run ./check which should be called in the pre-commit hook.

Third-party

  • oracall generates a server for calling stored procedures.

About

GO DRiver for ORacle DB

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

1,718 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GoPkgGoDevGo Report Cardcodecov

Go DRiver for ORacle

godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper, ODPI-C.

Build-time Requirements

  • Go 1.15
  • C compiler with CGO_ENABLED=1 - so cross-compilation is hard

Run-time Requirements

  • Oracle Client libraries - see ODPI-C

Although Oracle Client libraries are NOT required for compiling, they are needed at run time. Download the free Basic or Basic Light package from https://www.oracle.com/database/technologies/instant-client/downloads.html.

Rationale

With Go 1.9, driver-specific things are not needed, everything (I need) can be achieved with the standard database/sql library. Even calling stored procedures with OUT parameters, or sending/retrieving PL/SQL array types - just give a godror.PlSQLArrays Option within the parameters of Exec (but not in sql.Named)! For example, the array size of the returned PL/SQL arrays can be set with godror.ArraySize(2000) (default value is 1024).

Documentation

See Godror API Documentation and the Godror User Guide.

Installation

Run:

go get github.com/godror/godror@latest

Then install Oracle Client libraries and you're ready to go!

godror is cgo package. If you want to build your app using godror, you need gcc (a C compiler).

Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compile present within your path.

See Godror Installation for more information.

Connection

To connect to Oracle Database use sql.Open("godror", dataSourceName), where dataSourceName is a logfmt-encoded parameter list. Specify at least "user", "password" and "connectString". For example:

db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)

The connectString can be ANYTHING that SQL*Plus or Oracle Call Interface (OCI) accepts: a service name, an Easy Connect string like host:port/service_name, or a connect descriptor like (DESCRIPTION=...).

You can specify connection timeout seconds with "?connect_timeout=15" - Ping uses this timeout, NOT the Deadline in Context! Note that connect_timeout requires at least 19c client.

For more connection options, see Godor Connection Handling.

Extras

To use the godror-specific functions, you'll need a *godror.conn. That's what godror.DriverConn is for! See z_qrcn_test.go for using that to reach NewSubscription.

Calling stored procedures

Use ExecContext and mark each OUT parameter with sql.Out.

As sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR), you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Lob/Rows.

Using cursors returned by stored procedures

Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.

As sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Rows.

For examples, see Anthony Tuininga's presentation about Go (page 41)!

Caveats

sql.NullString

sql.NullString is not supported: Oracle DB does not differentiate between an empty string ("") and a NULL, so an

sql.NullString{String:"", Valid:true} == sql.NullString{String:"", Valid:false}

and this would be more confusing than not supporting sql.NullString at all.

Just use plain old string !

NUMBER

NUMBERs are transferred as string to Go under the hood. This ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits), and sql.Scan will hide this and Scan into your int64, float64 or string, as you wish.

For PLS_INTEGER and BINARY_INTEGER (PL/SQL data types) you can use int32.

CLOB, BLOB

From 2.9.0, LOBs are returned as string/[]byte by default (before it needed the ClobAsString() option). Now it's reversed, and the default is string, to get a Lob reader, give the LobAsReader() option.

Watch out, Oracle will error out if the CLOB is too large, and you have to use godror.Lob in such cases!

If you return Lob as a reader, watch out with sql.QueryRow, sql.QueryRowContext ! They close the statement right after you Scan from the returned *Row, the returned Lob will be invalid, producing getSize: ORA-00000: DPI-1002: invalid dpiLob handle.

So, use a separate Stmt or sql.QueryContext.

For writing a LOB, the LOB locator returned from the database is valid only till the Stmt is valid! So Prepare the statement for the retrieval, then Exec, and only Close the stmt iff you've finished with your LOB! For example, see z_lob_test.go, TestLOBAppend.

TIMESTAMP

As I couldn't make TIMESTAMP arrays work, all time.Time is bind as DATE, so fractional seconds are lost. A workaround is converting to string:

time.Now().Format("2-Jan-06 3:04:05.000000 PM")

See #121 under the old project.

Timezone

See the documentation - but for short, the database's OS' time zone is used, as that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently), then set the "location" in the connection string, or the Timezone in the ConnectionParams accord to your chosen timezone.

Stored procedure returning cursor (result set)

varrset1, rset2 driver.Rowsconstquery=`BEGIN Package.StoredProcA(123, :1, :2); END;`stmt, err:=db.PrepareContext(ctx, query)
iferr!=nil {
returnfmt.Errorf("%s: %w", query, err)
}
deferstmt.Close()
if_, err:=stmt.ExecContext(ctx, sql.Out{Dest: &rset1}, sql.Out{Dest: &rset2}); err!=nil {
log.Printf("Error running %q: %+v", query, err)
return
}
deferrset1.Close()
deferrset2.Close()
cols1:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests1:=make([]driver.Value, len(cols1))
for {
iferr:=rset1.Next(dests1); err!=nil {
iferr==io.EOF {
break
}
rset1.Close()
returnerr
}
fmt.Println(dests1)
}
cols2:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests2:=make([]driver.Value, len(cols2))
for {
iferr:=rset2.Next(dests2); err!=nil {
iferr==io.EOF {
break
}
rset2.Close()
returnerr
}
fmt.Println(dests2)
}

Context with Deadline/Timeout

TL;DR; *always close sql.Rows ASAP!

Creating a watchdog goroutine, done channel for each call of rows.Next kills performance, so we create only one watchdog goroutine, at the first rows.Next call. It is defused after rows.Close (or the cursor is exhausted).

If it is not defused, it will Break the currently executing OCI call on the connection, when the Context is canceled/timeouted. You should always call rows.Close ASAP, but if you experience random Breaks, remember this warning!

Contribute

Just as with other Go projects, you don't want to change the import paths, but you can hack on the library in place, just set up different remotes:

cd$GOPATH/src/github.com/godror/godror
git remote add upstream https://github.com/godror/godror.git
git fetch upstream
git checkout -b master upstream/master
git checkout -f master
git pull upstream master
git remote add fork git@github.com:mygithubacc/godror
git checkout -b newfeature upstream/master

Change, experiment as you wish. Then run

git commit -m 'my great changes'*.go
git push fork newfeature

and you're ready to send a GitHub Pull Request from the github.com/mygithubacc/godror branch called newfeature.

Pre-commit

Download a staticcheckrelease and add this to .git/hooks/pre-commit:

#!/bin/shset -e
output="$(gofmt -l "$@")"if [ -n"$output" ];thenecho>&2"Go files must be formatted with gofmt. Please run:"forfin$output;doecho>&2" gofmt -w $PWD/$f"doneexit 1
fi
go run ./check
exec staticcheck

Guidelines

As ODPI stores the error buffer in a thread-local-storage, we must ensure that the error is retrieved on the same thread as the prvious function executed on.

This means we have to encapsulate each execute-then-retrieve-error sequence in runtime.LockOSThread() and runtime.UnlockOSThread(). For details, see #120.

This is automatically detected by go run ./check which should be called in the pre-commit hook.

Third-party

  • oracall generates a server for calling stored procedures.

About

GO DRiver for ORacle DB

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

1,718 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GoPkgGoDevGo Report Cardcodecov

Go DRiver for ORacle

godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper, ODPI-C.

Build-time Requirements

  • Go 1.15
  • C compiler with CGO_ENABLED=1 - so cross-compilation is hard

Run-time Requirements

  • Oracle Client libraries - see ODPI-C

Although Oracle Client libraries are NOT required for compiling, they are needed at run time. Download the free Basic or Basic Light package from https://www.oracle.com/database/technologies/instant-client/downloads.html.

Rationale

With Go 1.9, driver-specific things are not needed, everything (I need) can be achieved with the standard database/sql library. Even calling stored procedures with OUT parameters, or sending/retrieving PL/SQL array types - just give a godror.PlSQLArrays Option within the parameters of Exec (but not in sql.Named)! For example, the array size of the returned PL/SQL arrays can be set with godror.ArraySize(2000) (default value is 1024).

Documentation

See Godror API Documentation and the Godror User Guide.

Installation

Run:

go get github.com/godror/godror@latest

Then install Oracle Client libraries and you're ready to go!

godror is cgo package. If you want to build your app using godror, you need gcc (a C compiler).

Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compile present within your path.

See Godror Installation for more information.

Connection

To connect to Oracle Database use sql.Open("godror", dataSourceName), where dataSourceName is a logfmt-encoded parameter list. Specify at least "user", "password" and "connectString". For example:

db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)

The connectString can be ANYTHING that SQL*Plus or Oracle Call Interface (OCI) accepts: a service name, an Easy Connect string like host:port/service_name, or a connect descriptor like (DESCRIPTION=...).

You can specify connection timeout seconds with "?connect_timeout=15" - Ping uses this timeout, NOT the Deadline in Context! Note that connect_timeout requires at least 19c client.

For more connection options, see Godor Connection Handling.

Extras

To use the godror-specific functions, you'll need a *godror.conn. That's what godror.DriverConn is for! See z_qrcn_test.go for using that to reach NewSubscription.

Calling stored procedures

Use ExecContext and mark each OUT parameter with sql.Out.

As sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR), you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Lob/Rows.

Using cursors returned by stored procedures

Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.

As sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Rows.

For examples, see Anthony Tuininga's presentation about Go (page 41)!

Caveats

sql.NullString

sql.NullString is not supported: Oracle DB does not differentiate between an empty string ("") and a NULL, so an

sql.NullString{String:"", Valid:true} == sql.NullString{String:"", Valid:false}

and this would be more confusing than not supporting sql.NullString at all.

Just use plain old string !

NUMBER

NUMBERs are transferred as string to Go under the hood. This ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits), and sql.Scan will hide this and Scan into your int64, float64 or string, as you wish.

For PLS_INTEGER and BINARY_INTEGER (PL/SQL data types) you can use int32.

CLOB, BLOB

From 2.9.0, LOBs are returned as string/[]byte by default (before it needed the ClobAsString() option). Now it's reversed, and the default is string, to get a Lob reader, give the LobAsReader() option.

Watch out, Oracle will error out if the CLOB is too large, and you have to use godror.Lob in such cases!

If you return Lob as a reader, watch out with sql.QueryRow, sql.QueryRowContext ! They close the statement right after you Scan from the returned *Row, the returned Lob will be invalid, producing getSize: ORA-00000: DPI-1002: invalid dpiLob handle.

So, use a separate Stmt or sql.QueryContext.

For writing a LOB, the LOB locator returned from the database is valid only till the Stmt is valid! So Prepare the statement for the retrieval, then Exec, and only Close the stmt iff you've finished with your LOB! For example, see z_lob_test.go, TestLOBAppend.

TIMESTAMP

As I couldn't make TIMESTAMP arrays work, all time.Time is bind as DATE, so fractional seconds are lost. A workaround is converting to string:

time.Now().Format("2-Jan-06 3:04:05.000000 PM")

See #121 under the old project.

Timezone

See the documentation - but for short, the database's OS' time zone is used, as that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently), then set the "location" in the connection string, or the Timezone in the ConnectionParams accord to your chosen timezone.

Stored procedure returning cursor (result set)

varrset1, rset2 driver.Rowsconstquery=`BEGIN Package.StoredProcA(123, :1, :2); END;`stmt, err:=db.PrepareContext(ctx, query)
iferr!=nil {
returnfmt.Errorf("%s: %w", query, err)
}
deferstmt.Close()
if_, err:=stmt.ExecContext(ctx, sql.Out{Dest: &rset1}, sql.Out{Dest: &rset2}); err!=nil {
log.Printf("Error running %q: %+v", query, err)
return
}
deferrset1.Close()
deferrset2.Close()
cols1:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests1:=make([]driver.Value, len(cols1))
for {
iferr:=rset1.Next(dests1); err!=nil {
iferr==io.EOF {
break
}
rset1.Close()
returnerr
}
fmt.Println(dests1)
}
cols2:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests2:=make([]driver.Value, len(cols2))
for {
iferr:=rset2.Next(dests2); err!=nil {
iferr==io.EOF {
break
}
rset2.Close()
returnerr
}
fmt.Println(dests2)
}

Context with Deadline/Timeout

TL;DR; *always close sql.Rows ASAP!

Creating a watchdog goroutine, done channel for each call of rows.Next kills performance, so we create only one watchdog goroutine, at the first rows.Next call. It is defused after rows.Close (or the cursor is exhausted).

If it is not defused, it will Break the currently executing OCI call on the connection, when the Context is canceled/timeouted. You should always call rows.Close ASAP, but if you experience random Breaks, remember this warning!

Contribute

Just as with other Go projects, you don't want to change the import paths, but you can hack on the library in place, just set up different remotes:

cd$GOPATH/src/github.com/godror/godror
git remote add upstream https://github.com/godror/godror.git
git fetch upstream
git checkout -b master upstream/master
git checkout -f master
git pull upstream master
git remote add fork git@github.com:mygithubacc/godror
git checkout -b newfeature upstream/master

Change, experiment as you wish. Then run

git commit -m 'my great changes'*.go
git push fork newfeature

and you're ready to send a GitHub Pull Request from the github.com/mygithubacc/godror branch called newfeature.

Pre-commit

Download a staticcheckrelease and add this to .git/hooks/pre-commit:

#!/bin/shset -e
output="$(gofmt -l "$@")"if [ -n"$output" ];thenecho>&2"Go files must be formatted with gofmt. Please run:"forfin$output;doecho>&2" gofmt -w $PWD/$f"doneexit 1
fi
go run ./check
exec staticcheck

Guidelines

As ODPI stores the error buffer in a thread-local-storage, we must ensure that the error is retrieved on the same thread as the prvious function executed on.

This means we have to encapsulate each execute-then-retrieve-error sequence in runtime.LockOSThread() and runtime.UnlockOSThread(). For details, see #120.

This is automatically detected by go run ./check which should be called in the pre-commit hook.

Third-party

  • oracall generates a server for calling stored procedures.

About

GO DRiver for ORacle DB

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

1,718 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GoPkgGoDevGo Report Cardcodecov

Go DRiver for ORacle

godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper, ODPI-C.

Build-time Requirements

  • Go 1.15
  • C compiler with CGO_ENABLED=1 - so cross-compilation is hard

Run-time Requirements

  • Oracle Client libraries - see ODPI-C

Although Oracle Client libraries are NOT required for compiling, they are needed at run time. Download the free Basic or Basic Light package from https://www.oracle.com/database/technologies/instant-client/downloads.html.

Rationale

With Go 1.9, driver-specific things are not needed, everything (I need) can be achieved with the standard database/sql library. Even calling stored procedures with OUT parameters, or sending/retrieving PL/SQL array types - just give a godror.PlSQLArrays Option within the parameters of Exec (but not in sql.Named)! For example, the array size of the returned PL/SQL arrays can be set with godror.ArraySize(2000) (default value is 1024).

Documentation

See Godror API Documentation and the Godror User Guide.

Installation

Run:

go get github.com/godror/godror@latest

Then install Oracle Client libraries and you're ready to go!

godror is cgo package. If you want to build your app using godror, you need gcc (a C compiler).

Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compile present within your path.

See Godror Installation for more information.

Connection

To connect to Oracle Database use sql.Open("godror", dataSourceName), where dataSourceName is a logfmt-encoded parameter list. Specify at least "user", "password" and "connectString". For example:

db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)

The connectString can be ANYTHING that SQL*Plus or Oracle Call Interface (OCI) accepts: a service name, an Easy Connect string like host:port/service_name, or a connect descriptor like (DESCRIPTION=...).

You can specify connection timeout seconds with "?connect_timeout=15" - Ping uses this timeout, NOT the Deadline in Context! Note that connect_timeout requires at least 19c client.

For more connection options, see Godor Connection Handling.

Extras

To use the godror-specific functions, you'll need a *godror.conn. That's what godror.DriverConn is for! See z_qrcn_test.go for using that to reach NewSubscription.

Calling stored procedures

Use ExecContext and mark each OUT parameter with sql.Out.

As sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR), you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Lob/Rows.

Using cursors returned by stored procedures

Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.

As sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Rows.

For examples, see Anthony Tuininga's presentation about Go (page 41)!

Caveats

sql.NullString

sql.NullString is not supported: Oracle DB does not differentiate between an empty string ("") and a NULL, so an

sql.NullString{String:"", Valid:true} == sql.NullString{String:"", Valid:false}

and this would be more confusing than not supporting sql.NullString at all.

Just use plain old string !

NUMBER

NUMBERs are transferred as string to Go under the hood. This ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits), and sql.Scan will hide this and Scan into your int64, float64 or string, as you wish.

For PLS_INTEGER and BINARY_INTEGER (PL/SQL data types) you can use int32.

CLOB, BLOB

From 2.9.0, LOBs are returned as string/[]byte by default (before it needed the ClobAsString() option). Now it's reversed, and the default is string, to get a Lob reader, give the LobAsReader() option.

Watch out, Oracle will error out if the CLOB is too large, and you have to use godror.Lob in such cases!

If you return Lob as a reader, watch out with sql.QueryRow, sql.QueryRowContext ! They close the statement right after you Scan from the returned *Row, the returned Lob will be invalid, producing getSize: ORA-00000: DPI-1002: invalid dpiLob handle.

So, use a separate Stmt or sql.QueryContext.

For writing a LOB, the LOB locator returned from the database is valid only till the Stmt is valid! So Prepare the statement for the retrieval, then Exec, and only Close the stmt iff you've finished with your LOB! For example, see z_lob_test.go, TestLOBAppend.

TIMESTAMP

As I couldn't make TIMESTAMP arrays work, all time.Time is bind as DATE, so fractional seconds are lost. A workaround is converting to string:

time.Now().Format("2-Jan-06 3:04:05.000000 PM")

See #121 under the old project.

Timezone

See the documentation - but for short, the database's OS' time zone is used, as that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently), then set the "location" in the connection string, or the Timezone in the ConnectionParams accord to your chosen timezone.

Stored procedure returning cursor (result set)

varrset1, rset2 driver.Rowsconstquery=`BEGIN Package.StoredProcA(123, :1, :2); END;`stmt, err:=db.PrepareContext(ctx, query)
iferr!=nil {
returnfmt.Errorf("%s: %w", query, err)
}
deferstmt.Close()
if_, err:=stmt.ExecContext(ctx, sql.Out{Dest: &rset1}, sql.Out{Dest: &rset2}); err!=nil {
log.Printf("Error running %q: %+v", query, err)
return
}
deferrset1.Close()
deferrset2.Close()
cols1:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests1:=make([]driver.Value, len(cols1))
for {
iferr:=rset1.Next(dests1); err!=nil {
iferr==io.EOF {
break
}
rset1.Close()
returnerr
}
fmt.Println(dests1)
}
cols2:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests2:=make([]driver.Value, len(cols2))
for {
iferr:=rset2.Next(dests2); err!=nil {
iferr==io.EOF {
break
}
rset2.Close()
returnerr
}
fmt.Println(dests2)
}

Context with Deadline/Timeout

TL;DR; *always close sql.Rows ASAP!

Creating a watchdog goroutine, done channel for each call of rows.Next kills performance, so we create only one watchdog goroutine, at the first rows.Next call. It is defused after rows.Close (or the cursor is exhausted).

If it is not defused, it will Break the currently executing OCI call on the connection, when the Context is canceled/timeouted. You should always call rows.Close ASAP, but if you experience random Breaks, remember this warning!

Contribute

Just as with other Go projects, you don't want to change the import paths, but you can hack on the library in place, just set up different remotes:

cd$GOPATH/src/github.com/godror/godror
git remote add upstream https://github.com/godror/godror.git
git fetch upstream
git checkout -b master upstream/master
git checkout -f master
git pull upstream master
git remote add fork git@github.com:mygithubacc/godror
git checkout -b newfeature upstream/master

Change, experiment as you wish. Then run

git commit -m 'my great changes'*.go
git push fork newfeature

and you're ready to send a GitHub Pull Request from the github.com/mygithubacc/godror branch called newfeature.

Pre-commit

Download a staticcheckrelease and add this to .git/hooks/pre-commit:

#!/bin/shset -e
output="$(gofmt -l "$@")"if [ -n"$output" ];thenecho>&2"Go files must be formatted with gofmt. Please run:"forfin$output;doecho>&2" gofmt -w $PWD/$f"doneexit 1
fi
go run ./check
exec staticcheck

Guidelines

As ODPI stores the error buffer in a thread-local-storage, we must ensure that the error is retrieved on the same thread as the prvious function executed on.

This means we have to encapsulate each execute-then-retrieve-error sequence in runtime.LockOSThread() and runtime.UnlockOSThread(). For details, see #120.

This is automatically detected by go run ./check which should be called in the pre-commit hook.

Third-party

  • oracall generates a server for calling stored procedures.

About

GO DRiver for ORacle DB

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

1,718 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GoPkgGoDevGo Report Cardcodecov

Go DRiver for ORacle

godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper, ODPI-C.

Build-time Requirements

  • Go 1.15
  • C compiler with CGO_ENABLED=1 - so cross-compilation is hard

Run-time Requirements

  • Oracle Client libraries - see ODPI-C

Although Oracle Client libraries are NOT required for compiling, they are needed at run time. Download the free Basic or Basic Light package from https://www.oracle.com/database/technologies/instant-client/downloads.html.

Rationale

With Go 1.9, driver-specific things are not needed, everything (I need) can be achieved with the standard database/sql library. Even calling stored procedures with OUT parameters, or sending/retrieving PL/SQL array types - just give a godror.PlSQLArrays Option within the parameters of Exec (but not in sql.Named)! For example, the array size of the returned PL/SQL arrays can be set with godror.ArraySize(2000) (default value is 1024).

Documentation

See Godror API Documentation and the Godror User Guide.

Installation

Run:

go get github.com/godror/godror@latest

Then install Oracle Client libraries and you're ready to go!

godror is cgo package. If you want to build your app using godror, you need gcc (a C compiler).

Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compile present within your path.

See Godror Installation for more information.

Connection

To connect to Oracle Database use sql.Open("godror", dataSourceName), where dataSourceName is a logfmt-encoded parameter list. Specify at least "user", "password" and "connectString". For example:

db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)

The connectString can be ANYTHING that SQL*Plus or Oracle Call Interface (OCI) accepts: a service name, an Easy Connect string like host:port/service_name, or a connect descriptor like (DESCRIPTION=...).

You can specify connection timeout seconds with "?connect_timeout=15" - Ping uses this timeout, NOT the Deadline in Context! Note that connect_timeout requires at least 19c client.

For more connection options, see Godor Connection Handling.

Extras

To use the godror-specific functions, you'll need a *godror.conn. That's what godror.DriverConn is for! See z_qrcn_test.go for using that to reach NewSubscription.

Calling stored procedures

Use ExecContext and mark each OUT parameter with sql.Out.

As sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR), you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Lob/Rows.

Using cursors returned by stored procedures

Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.

As sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Rows.

For examples, see Anthony Tuininga's presentation about Go (page 41)!

Caveats

sql.NullString

sql.NullString is not supported: Oracle DB does not differentiate between an empty string ("") and a NULL, so an

sql.NullString{String:"", Valid:true} == sql.NullString{String:"", Valid:false}

and this would be more confusing than not supporting sql.NullString at all.

Just use plain old string !

NUMBER

NUMBERs are transferred as string to Go under the hood. This ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits), and sql.Scan will hide this and Scan into your int64, float64 or string, as you wish.

For PLS_INTEGER and BINARY_INTEGER (PL/SQL data types) you can use int32.

CLOB, BLOB

From 2.9.0, LOBs are returned as string/[]byte by default (before it needed the ClobAsString() option). Now it's reversed, and the default is string, to get a Lob reader, give the LobAsReader() option.

Watch out, Oracle will error out if the CLOB is too large, and you have to use godror.Lob in such cases!

If you return Lob as a reader, watch out with sql.QueryRow, sql.QueryRowContext ! They close the statement right after you Scan from the returned *Row, the returned Lob will be invalid, producing getSize: ORA-00000: DPI-1002: invalid dpiLob handle.

So, use a separate Stmt or sql.QueryContext.

For writing a LOB, the LOB locator returned from the database is valid only till the Stmt is valid! So Prepare the statement for the retrieval, then Exec, and only Close the stmt iff you've finished with your LOB! For example, see z_lob_test.go, TestLOBAppend.

TIMESTAMP

As I couldn't make TIMESTAMP arrays work, all time.Time is bind as DATE, so fractional seconds are lost. A workaround is converting to string:

time.Now().Format("2-Jan-06 3:04:05.000000 PM")

See #121 under the old project.

Timezone

See the documentation - but for short, the database's OS' time zone is used, as that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently), then set the "location" in the connection string, or the Timezone in the ConnectionParams accord to your chosen timezone.

Stored procedure returning cursor (result set)

varrset1, rset2 driver.Rowsconstquery=`BEGIN Package.StoredProcA(123, :1, :2); END;`stmt, err:=db.PrepareContext(ctx, query)
iferr!=nil {
returnfmt.Errorf("%s: %w", query, err)
}
deferstmt.Close()
if_, err:=stmt.ExecContext(ctx, sql.Out{Dest: &rset1}, sql.Out{Dest: &rset2}); err!=nil {
log.Printf("Error running %q: %+v", query, err)
return
}
deferrset1.Close()
deferrset2.Close()
cols1:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests1:=make([]driver.Value, len(cols1))
for {
iferr:=rset1.Next(dests1); err!=nil {
iferr==io.EOF {
break
}
rset1.Close()
returnerr
}
fmt.Println(dests1)
}
cols2:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests2:=make([]driver.Value, len(cols2))
for {
iferr:=rset2.Next(dests2); err!=nil {
iferr==io.EOF {
break
}
rset2.Close()
returnerr
}
fmt.Println(dests2)
}

Context with Deadline/Timeout

TL;DR; *always close sql.Rows ASAP!

Creating a watchdog goroutine, done channel for each call of rows.Next kills performance, so we create only one watchdog goroutine, at the first rows.Next call. It is defused after rows.Close (or the cursor is exhausted).

If it is not defused, it will Break the currently executing OCI call on the connection, when the Context is canceled/timeouted. You should always call rows.Close ASAP, but if you experience random Breaks, remember this warning!

Contribute

Just as with other Go projects, you don't want to change the import paths, but you can hack on the library in place, just set up different remotes:

cd$GOPATH/src/github.com/godror/godror
git remote add upstream https://github.com/godror/godror.git
git fetch upstream
git checkout -b master upstream/master
git checkout -f master
git pull upstream master
git remote add fork git@github.com:mygithubacc/godror
git checkout -b newfeature upstream/master

Change, experiment as you wish. Then run

git commit -m 'my great changes'*.go
git push fork newfeature

and you're ready to send a GitHub Pull Request from the github.com/mygithubacc/godror branch called newfeature.

Pre-commit

Download a staticcheckrelease and add this to .git/hooks/pre-commit:

#!/bin/shset -e
output="$(gofmt -l "$@")"if [ -n"$output" ];thenecho>&2"Go files must be formatted with gofmt. Please run:"forfin$output;doecho>&2" gofmt -w $PWD/$f"doneexit 1
fi
go run ./check
exec staticcheck

Guidelines

As ODPI stores the error buffer in a thread-local-storage, we must ensure that the error is retrieved on the same thread as the prvious function executed on.

This means we have to encapsulate each execute-then-retrieve-error sequence in runtime.LockOSThread() and runtime.UnlockOSThread(). For details, see #120.

This is automatically detected by go run ./check which should be called in the pre-commit hook.

Third-party

  • oracall generates a server for calling stored procedures.

About

GO DRiver for ORacle DB

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

1,718 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GoPkgGoDevGo Report Cardcodecov

Go DRiver for ORacle

godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper, ODPI-C.

Build-time Requirements

  • Go 1.15
  • C compiler with CGO_ENABLED=1 - so cross-compilation is hard

Run-time Requirements

  • Oracle Client libraries - see ODPI-C

Although Oracle Client libraries are NOT required for compiling, they are needed at run time. Download the free Basic or Basic Light package from https://www.oracle.com/database/technologies/instant-client/downloads.html.

Rationale

With Go 1.9, driver-specific things are not needed, everything (I need) can be achieved with the standard database/sql library. Even calling stored procedures with OUT parameters, or sending/retrieving PL/SQL array types - just give a godror.PlSQLArrays Option within the parameters of Exec (but not in sql.Named)! For example, the array size of the returned PL/SQL arrays can be set with godror.ArraySize(2000) (default value is 1024).

Documentation

See Godror API Documentation and the Godror User Guide.

Installation

Run:

go get github.com/godror/godror@latest

Then install Oracle Client libraries and you're ready to go!

godror is cgo package. If you want to build your app using godror, you need gcc (a C compiler).

Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compile present within your path.

See Godror Installation for more information.

Connection

To connect to Oracle Database use sql.Open("godror", dataSourceName), where dataSourceName is a logfmt-encoded parameter list. Specify at least "user", "password" and "connectString". For example:

db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)

The connectString can be ANYTHING that SQL*Plus or Oracle Call Interface (OCI) accepts: a service name, an Easy Connect string like host:port/service_name, or a connect descriptor like (DESCRIPTION=...).

You can specify connection timeout seconds with "?connect_timeout=15" - Ping uses this timeout, NOT the Deadline in Context! Note that connect_timeout requires at least 19c client.

For more connection options, see Godor Connection Handling.

Extras

To use the godror-specific functions, you'll need a *godror.conn. That's what godror.DriverConn is for! See z_qrcn_test.go for using that to reach NewSubscription.

Calling stored procedures

Use ExecContext and mark each OUT parameter with sql.Out.

As sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR), you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Lob/Rows.

Using cursors returned by stored procedures

Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.

As sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Rows.

For examples, see Anthony Tuininga's presentation about Go (page 41)!

Caveats

sql.NullString

sql.NullString is not supported: Oracle DB does not differentiate between an empty string ("") and a NULL, so an

sql.NullString{String:"", Valid:true} == sql.NullString{String:"", Valid:false}

and this would be more confusing than not supporting sql.NullString at all.

Just use plain old string !

NUMBER

NUMBERs are transferred as string to Go under the hood. This ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits), and sql.Scan will hide this and Scan into your int64, float64 or string, as you wish.

For PLS_INTEGER and BINARY_INTEGER (PL/SQL data types) you can use int32.

CLOB, BLOB

From 2.9.0, LOBs are returned as string/[]byte by default (before it needed the ClobAsString() option). Now it's reversed, and the default is string, to get a Lob reader, give the LobAsReader() option.

Watch out, Oracle will error out if the CLOB is too large, and you have to use godror.Lob in such cases!

If you return Lob as a reader, watch out with sql.QueryRow, sql.QueryRowContext ! They close the statement right after you Scan from the returned *Row, the returned Lob will be invalid, producing getSize: ORA-00000: DPI-1002: invalid dpiLob handle.

So, use a separate Stmt or sql.QueryContext.

For writing a LOB, the LOB locator returned from the database is valid only till the Stmt is valid! So Prepare the statement for the retrieval, then Exec, and only Close the stmt iff you've finished with your LOB! For example, see z_lob_test.go, TestLOBAppend.

TIMESTAMP

As I couldn't make TIMESTAMP arrays work, all time.Time is bind as DATE, so fractional seconds are lost. A workaround is converting to string:

time.Now().Format("2-Jan-06 3:04:05.000000 PM")

See #121 under the old project.

Timezone

See the documentation - but for short, the database's OS' time zone is used, as that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently), then set the "location" in the connection string, or the Timezone in the ConnectionParams accord to your chosen timezone.

Stored procedure returning cursor (result set)

varrset1, rset2 driver.Rowsconstquery=`BEGIN Package.StoredProcA(123, :1, :2); END;`stmt, err:=db.PrepareContext(ctx, query)
iferr!=nil {
returnfmt.Errorf("%s: %w", query, err)
}
deferstmt.Close()
if_, err:=stmt.ExecContext(ctx, sql.Out{Dest: &rset1}, sql.Out{Dest: &rset2}); err!=nil {
log.Printf("Error running %q: %+v", query, err)
return
}
deferrset1.Close()
deferrset2.Close()
cols1:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests1:=make([]driver.Value, len(cols1))
for {
iferr:=rset1.Next(dests1); err!=nil {
iferr==io.EOF {
break
}
rset1.Close()
returnerr
}
fmt.Println(dests1)
}
cols2:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests2:=make([]driver.Value, len(cols2))
for {
iferr:=rset2.Next(dests2); err!=nil {
iferr==io.EOF {
break
}
rset2.Close()
returnerr
}
fmt.Println(dests2)
}

Context with Deadline/Timeout

TL;DR; *always close sql.Rows ASAP!

Creating a watchdog goroutine, done channel for each call of rows.Next kills performance, so we create only one watchdog goroutine, at the first rows.Next call. It is defused after rows.Close (or the cursor is exhausted).

If it is not defused, it will Break the currently executing OCI call on the connection, when the Context is canceled/timeouted. You should always call rows.Close ASAP, but if you experience random Breaks, remember this warning!

Contribute

Just as with other Go projects, you don't want to change the import paths, but you can hack on the library in place, just set up different remotes:

cd$GOPATH/src/github.com/godror/godror
git remote add upstream https://github.com/godror/godror.git
git fetch upstream
git checkout -b master upstream/master
git checkout -f master
git pull upstream master
git remote add fork git@github.com:mygithubacc/godror
git checkout -b newfeature upstream/master

Change, experiment as you wish. Then run

git commit -m 'my great changes'*.go
git push fork newfeature

and you're ready to send a GitHub Pull Request from the github.com/mygithubacc/godror branch called newfeature.

Pre-commit

Download a staticcheckrelease and add this to .git/hooks/pre-commit:

#!/bin/shset -e
output="$(gofmt -l "$@")"if [ -n"$output" ];thenecho>&2"Go files must be formatted with gofmt. Please run:"forfin$output;doecho>&2" gofmt -w $PWD/$f"doneexit 1
fi
go run ./check
exec staticcheck

Guidelines

As ODPI stores the error buffer in a thread-local-storage, we must ensure that the error is retrieved on the same thread as the prvious function executed on.

This means we have to encapsulate each execute-then-retrieve-error sequence in runtime.LockOSThread() and runtime.UnlockOSThread(). For details, see #120.

This is automatically detected by go run ./check which should be called in the pre-commit hook.

Third-party

  • oracall generates a server for calling stored procedures.

About

GO DRiver for ORacle DB

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

1,718 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

GoPkgGoDevGo Report Cardcodecov

Go DRiver for ORacle

godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper, ODPI-C.

Build-time Requirements

  • Go 1.15
  • C compiler with CGO_ENABLED=1 - so cross-compilation is hard

Run-time Requirements

  • Oracle Client libraries - see ODPI-C

Although Oracle Client libraries are NOT required for compiling, they are needed at run time. Download the free Basic or Basic Light package from https://www.oracle.com/database/technologies/instant-client/downloads.html.

Rationale

With Go 1.9, driver-specific things are not needed, everything (I need) can be achieved with the standard database/sql library. Even calling stored procedures with OUT parameters, or sending/retrieving PL/SQL array types - just give a godror.PlSQLArrays Option within the parameters of Exec (but not in sql.Named)! For example, the array size of the returned PL/SQL arrays can be set with godror.ArraySize(2000) (default value is 1024).

Documentation

See Godror API Documentation and the Godror User Guide.

Installation

Run:

go get github.com/godror/godror@latest

Then install Oracle Client libraries and you're ready to go!

godror is cgo package. If you want to build your app using godror, you need gcc (a C compiler).

Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compile present within your path.

See Godror Installation for more information.

Connection

To connect to Oracle Database use sql.Open("godror", dataSourceName), where dataSourceName is a logfmt-encoded parameter list. Specify at least "user", "password" and "connectString". For example:

db, err := sql.Open("godror", `user="scott" password="tiger" connectString="dbhost:1521/orclpdb1"`)

The connectString can be ANYTHING that SQL*Plus or Oracle Call Interface (OCI) accepts: a service name, an Easy Connect string like host:port/service_name, or a connect descriptor like (DESCRIPTION=...).

You can specify connection timeout seconds with "?connect_timeout=15" - Ping uses this timeout, NOT the Deadline in Context! Note that connect_timeout requires at least 19c client.

For more connection options, see Godor Connection Handling.

Extras

To use the godror-specific functions, you'll need a *godror.conn. That's what godror.DriverConn is for! See z_qrcn_test.go for using that to reach NewSubscription.

Calling stored procedures

Use ExecContext and mark each OUT parameter with sql.Out.

As sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR), you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Lob/Rows.

Using cursors returned by stored procedures

Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.

As sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: Prepare the statement, and Close only after finished with the Rows.

For examples, see Anthony Tuininga's presentation about Go (page 41)!

Caveats

sql.NullString

sql.NullString is not supported: Oracle DB does not differentiate between an empty string ("") and a NULL, so an

sql.NullString{String:"", Valid:true} == sql.NullString{String:"", Valid:false}

and this would be more confusing than not supporting sql.NullString at all.

Just use plain old string !

NUMBER

NUMBERs are transferred as string to Go under the hood. This ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits), and sql.Scan will hide this and Scan into your int64, float64 or string, as you wish.

For PLS_INTEGER and BINARY_INTEGER (PL/SQL data types) you can use int32.

CLOB, BLOB

From 2.9.0, LOBs are returned as string/[]byte by default (before it needed the ClobAsString() option). Now it's reversed, and the default is string, to get a Lob reader, give the LobAsReader() option.

Watch out, Oracle will error out if the CLOB is too large, and you have to use godror.Lob in such cases!

If you return Lob as a reader, watch out with sql.QueryRow, sql.QueryRowContext ! They close the statement right after you Scan from the returned *Row, the returned Lob will be invalid, producing getSize: ORA-00000: DPI-1002: invalid dpiLob handle.

So, use a separate Stmt or sql.QueryContext.

For writing a LOB, the LOB locator returned from the database is valid only till the Stmt is valid! So Prepare the statement for the retrieval, then Exec, and only Close the stmt iff you've finished with your LOB! For example, see z_lob_test.go, TestLOBAppend.

TIMESTAMP

As I couldn't make TIMESTAMP arrays work, all time.Time is bind as DATE, so fractional seconds are lost. A workaround is converting to string:

time.Now().Format("2-Jan-06 3:04:05.000000 PM")

See #121 under the old project.

Timezone

See the documentation - but for short, the database's OS' time zone is used, as that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently), then set the "location" in the connection string, or the Timezone in the ConnectionParams accord to your chosen timezone.

Stored procedure returning cursor (result set)

varrset1, rset2 driver.Rowsconstquery=`BEGIN Package.StoredProcA(123, :1, :2); END;`stmt, err:=db.PrepareContext(ctx, query)
iferr!=nil {
returnfmt.Errorf("%s: %w", query, err)
}
deferstmt.Close()
if_, err:=stmt.ExecContext(ctx, sql.Out{Dest: &rset1}, sql.Out{Dest: &rset2}); err!=nil {
log.Printf("Error running %q: %+v", query, err)
return
}
deferrset1.Close()
deferrset2.Close()
cols1:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests1:=make([]driver.Value, len(cols1))
for {
iferr:=rset1.Next(dests1); err!=nil {
iferr==io.EOF {
break
}
rset1.Close()
returnerr
}
fmt.Println(dests1)
}
cols2:=rset1.(driver.RowsColumnTypeScanType).Columns()
dests2:=make([]driver.Value, len(cols2))
for {
iferr:=rset2.Next(dests2); err!=nil {
iferr==io.EOF {
break
}
rset2.Close()
returnerr
}
fmt.Println(dests2)
}

Context with Deadline/Timeout

TL;DR; *always close sql.Rows ASAP!

Creating a watchdog goroutine, done channel for each call of rows.Next kills performance, so we create only one watchdog goroutine, at the first rows.Next call. It is defused after rows.Close (or the cursor is exhausted).

If it is not defused, it will Break the currently executing OCI call on the connection, when the Context is canceled/timeouted. You should always call rows.Close ASAP, but if you experience random Breaks, remember this warning!

Contribute

Just as with other Go projects, you don't want to change the import paths, but you can hack on the library in place, just set up different remotes:

cd$GOPATH/src/github.com/godror/godror
git remote add upstream https://github.com/godror/godror.git
git fetch upstream
git checkout -b master upstream/master
git checkout -f master
git pull upstream master
git remote add fork git@github.com:mygithubacc/godror
git checkout -b newfeature upstream/master

Change, experiment as you wish. Then run

git commit -m 'my great changes'*.go
git push fork newfeature

and you're ready to send a GitHub Pull Request from the github.com/mygithubacc/godror branch called newfeature.

Pre-commit

Download a staticcheckrelease and add this to .git/hooks/pre-commit:

#!/bin/shset -e
output="$(gofmt -l "$@")"if [ -n"$output" ];thenecho>&2"Go files must be formatted with gofmt. Please run:"forfin$output;doecho>&2" gofmt -w $PWD/$f"doneexit 1
fi
go run ./check
exec staticcheck

Guidelines

As ODPI stores the error buffer in a thread-local-storage, we must ensure that the error is retrieved on the same thread as the prvious function executed on.

This means we have to encapsulate each execute-then-retrieve-error sequence in runtime.LockOSThread() and runtime.UnlockOSThread(). For details, see #120.

This is automatically detected by go run ./check which should be called in the pre-commit hook.

Third-party

  • oracall generates a server for calling stored procedures.

About

GO DRiver for ORacle DB

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages