{"id":13412261,"url":"https://github.com/godror/godror","last_synced_at":"2025-03-14T18:31:06.986Z","repository":{"id":41374980,"uuid":"223268020","full_name":"godror/godror","owner":"godror","description":"GO DRiver for ORacle DB","archived":false,"fork":false,"pushed_at":"2024-07-24T05:50:25.000Z","size":2960,"stargazers_count":514,"open_issues_count":5,"forks_count":98,"subscribers_count":28,"default_branch":"main","last_synced_at":"2024-07-24T07:13:41.154Z","etag":null,"topics":["go","golang","oracle","oracle-db","sql"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/godror.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-21T21:23:17.000Z","updated_at":"2024-07-24T05:50:13.000Z","dependencies_parsed_at":"2023-02-19T06:46:03.672Z","dependency_job_id":"c6e8db31-5253-4362-9fd6-74e2a86c58cf","html_url":"https://github.com/godror/godror","commit_stats":null,"previous_names":[],"tags_count":118,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godror%2Fgodror","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godror%2Fgodror/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godror%2Fgodror/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godror%2Fgodror/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/godror","download_url":"https://codeload.github.com/godror/godror/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":213247969,"owners_count":15558654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","oracle","oracle-db","sql"],"created_at":"2024-07-30T20:01:22.738Z","updated_at":"2025-03-14T18:31:06.981Z","avatar_url":"https://github.com/godror.png","language":"C","funding_links":[],"categories":["Database Drivers","Data Integration Frameworks","Generators","数据库驱动程序","C","Relational Databases"],"sub_categories":["Relational Database Drivers","关系数据库驱动程序","Advanced Console UIs"],"readme":"![Go](https://github.com/godror/godror/workflows/Go/badge.svg)\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/godror/godror)](https://pkg.go.dev/github.com/godror/godror)\n[![Go Report Card](https://goreportcard.com/badge/github.com/godror/godror)](https://goreportcard.com/report/github.com/godror/godror)\n[![codecov](https://codecov.io/gh/godror/godror/branch/master/graph/badge.svg)](https://codecov.io/gh/godror/godror)\n\n# Go DRiver for ORacle\n\n[godror](https://godoc.org/pkg/github.com/godror/godror) is a package which is a\n[database/sql/driver.Driver](http://golang.org/pkg/database/sql/driver/#Driver)\nfor connecting to Oracle DB, using Anthony Tuininga's excellent OCI wrapper,\n[ODPI-C](https://www.github.com/oracle/odpi).\n\n## Build-time Requirements\n  - Go 1.15\n  - C compiler with `CGO_ENABLED=1` - so cross-compilation is hard\n\n## Run-time Requirements\n  - Oracle Client libraries - see [ODPI-C](https://oracle.github.io/odpi/doc/installation.html) \n\nAlthough Oracle Client libraries are NOT required for compiling, they *are*\nneeded at run time.  Download the free Basic or Basic Light package from\n\u003chttps://www.oracle.com/database/technologies/instant-client/downloads.html\u003e.\n\n## Rationale\n\nWith Go 1.9, driver-specific things are not needed, everything (I need) can be\nachieved with the standard _database/sql_ library. Even calling stored\nprocedures with OUT parameters, or sending/retrieving PL/SQL array types - just\ngive a `godror.PlSQLArrays` Option within the parameters of `Exec` (but not in sql.Named)! \nFor example, the array size of the returned PL/SQL arrays can be set with\n`godror.ArraySize(2000)` (default value is 1024).\n\n## Documentation\n\nSee [Godror API Documentation](https://pkg.go.dev/github.com/godror/godror?tab=doc) and\nthe [Godror User Guide](https://godror.github.io/godror/doc/contents.html).\n\n## Installation\n\nRun:\n\n```bash\ngo get github.com/godror/godror@latest\n```\n\nThen install Oracle Client libraries and you're ready to go!\n\ngodror is cgo package. \nIf you want to build your app using godror, you need gcc (a C compiler).\n\nImportant: because this is a CGO enabled package, \nyou are required to set the environment variable `CGO_ENABLED=1` \nand have a gcc compile present within your path.\n\nSee [Godror\nInstallation](https://godror.github.io/godror/doc/installation.html) for more information.\n\n## Connection\n\nTo connect to Oracle Database use `sql.Open(\"godror\", dataSourceName)`,\nwhere `dataSourceName` is a [logfmt](https://brandur.org/logfmt)-encoded\nparameter list.  Specify at least \"user\", \"password\" and \"connectString\".\nFor example:\n\n```\ndb, err := sql.Open(\"godror\", `user=\"scott\" password=\"tiger\" connectString=\"dbhost:1521/orclpdb1\"`)\n```\n\nThe `connectString` can be _ANYTHING_ that SQL*Plus or Oracle Call Interface\n(OCI) accepts: a service name, an [Easy Connect\nstring](https://download.oracle.com/ocomdocs/global/Oracle-Net-19c-Easy-Connect-Plus.pdf)\nlike `host:port/service_name`, or a connect descriptor like `(DESCRIPTION=...)`.\n\nYou can specify connection timeout seconds with \"?connect_timeout=15\" - Ping uses this timeout, NOT the Deadline in Context!\nNote that `connect_timeout` requires at least 19c client.\n\nFor more connection options, see [Godor Connection\nHandling](https://godror.github.io/godror/doc/connection.html).\n\n## Pooling\nOracle's OCI client (which this driver uses under the hood) has problems with fast connect-reconnect cycles,\nwhich may result in SIGSEGV in the C library. As this cannot be isolated from the Go program,\nplease use some kind of connection pooling - either db.SetMaxIdleConns with something bigger than 0,\nor the driver's built-in session pooling (standaloneConnection=0, poolMinSessions=1).\n\n## Extras\n\nTo use the godror-specific functions, you'll need a `*godror.conn`.\nThat's what `godror.DriverConn` is for!\nSee [z_qrcn_test.go](./z_qrcn_test.go) for using that to reach\n[NewSubscription](https://godoc.org/github.com/godror/godror#Subscription).\n\n### Calling stored procedures\n\nUse `ExecContext` and mark each OUT parameter with `sql.Out`.\n\nAs sql.DB will close the statement ASAP, for long-lived objects (LOB, REF CURSOR),\nyou have to keep the Stmt alive: Prepare the statement, \nand Close only after finished with the Lob/Rows.\n\n### Using cursors returned by stored procedures\n\nUse `ExecContext` and an `interface{}` or a `database/sql/driver.Rows` as the `sql.Out` destination,\nthen either use the `driver.Rows` interface,\nor transform it into a regular `*sql.Rows` with `godror.WrapRows`,\nor (since Go 1.12) just Scan into `*sql.Rows`.\n\nAs sql.DB will close the statemenet ASAP, you have to keep the Stmt alive: \nPrepare the statement, and Close only after finished with the Rows.\n\nFor examples, see Anthony Tuininga's\n[presentation about Go](https://static.rainfocus.com/oracle/oow19/sess/1567058525476001cK8G/PF/DEV6708-Using-the-Go-Language-for-Efficient-Oracle-Database-Applications_1568841171132001jI7d.pdf)\n(page 41)!\n\n## Caveats\n\n### sql.NullString\n\n`sql.NullString` is not supported: Oracle DB does not differentiate between\nan empty string (\"\") and a NULL, so an\n\n```go\nsql.NullString{String:\"\", Valid:true} == sql.NullString{String:\"\", Valid:false}\n```\n\nand this would be more confusing than not supporting `sql.NullString` at all.\n\nJust use plain old `string` !\n\n### NUMBER\n\n`NUMBER`s are transferred as `string` to Go under the hood.\nThis ensures that we don't lose any precision (Oracle's NUMBER has 38 decimal digits),\nand `sql.Scan` will hide this and `Scan` into your `int64`, `float64` or `string`, as you wish.\n\nFor `PLS_INTEGER` and `BINARY_INTEGER` (PL/SQL data types) you can use `int32`.\n\n### CLOB, BLOB\n\nFrom 2.9.0, LOBs are returned as string/[]byte by default (before it needed the `ClobAsString()` option).\nNow it's reversed, and the default is string, to get a Lob reader, give the `LobAsReader()` option.\n\nWatch out, Oracle will error out if the CLOB is too large, and you have to use `godror.Lob` in such cases!\n\nIf you return Lob as a reader, watch out with `sql.QueryRow`, `sql.QueryRowContext` !\nThey close the statement right after you `Scan` from the returned `*Row`, the returned `Lob` will be invalid, producing\n`getSize: ORA-00000: DPI-1002: invalid dpiLob handle`.\n\nSo, use a separate `Stmt` or `sql.QueryContext`.\n\nFor writing a LOB, the LOB locator returned from the database is valid only till the `Stmt` is valid!\nSo `Prepare` the statement for the retrieval, then `Exec`, and only `Close` the stmt iff you've finished with your LOB!\nFor example, see [z_lob_test.go](./z_lob_test.go), `TestLOBAppend`.\n\n### TIMESTAMP\n\nAs I couldn't make TIMESTAMP arrays work, all `time.Time` is bind as `DATE`, so fractional seconds\nare lost.\nA workaround is converting to string:\n\n```go\ntime.Now().Format(\"2-Jan-06 3:04:05.000000 PM\")\n```\n\nSee [#121 under the old project](https://github.com/go-goracle/goracle/issues/121).\n\n### Timezone\nSee the [documentation](./doc/timezone.md) - but for short, the database's OS' time zone is used,\nas that's what SYSDATE/SYSTIMESTAMP uses. If you want something different (because you fill DATE columns differently),\nthen set the \"location\" in  the connection string, or the `Timezone` in the `ConnectionParams` accord to your chosen timezone.\n\n### Stored procedure returning cursor (result set)\n```go\nvar rset1, rset2 driver.Rows\n\nconst query = `BEGIN Package.StoredProcA(123, :1, :2); END;`\n\nstmt, err := db.PrepareContext(ctx, query)\nif err != nil {\n    return fmt.Errorf(\"%s: %w\", query, err)\n}\ndefer stmt.Close()\nif _, err := stmt.ExecContext(ctx, sql.Out{Dest: \u0026rset1}, sql.Out{Dest: \u0026rset2}); err != nil {\n\tlog.Printf(\"Error running %q: %+v\", query, err)\n\treturn\n}\ndefer rset1.Close()\ndefer rset2.Close()\n\ncols1 := rset1.(driver.RowsColumnTypeScanType).Columns()\ndests1 := make([]driver.Value, len(cols1))\nfor {\n\tif err := rset1.Next(dests1); err != nil {\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\trset1.Close()\n\t\treturn err\n\t}\n\tfmt.Println(dests1)\n}\n\ncols2 := rset1.(driver.RowsColumnTypeScanType).Columns()\ndests2 := make([]driver.Value, len(cols2))\nfor {\n\tif err := rset2.Next(dests2); err != nil {\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\trset2.Close()\n\t\treturn err\n\t}\n\tfmt.Println(dests2)\n}\n```\n\n### Context with Deadline/Timeout\nTL;DR; *always close *sql.Rows ASAP!*\n\nCreating a watchdog goroutine, done channel for each call of `rows.Next` kills performance,\nso we create only one watchdog goroutine, at the first `rows.Next` call.\nIt is defused after `rows.Close` (or the cursor is exhausted).\n\nIf it is not defused, it will `Break` the currently executing OCI call on the connection,\nwhen the Context is canceled/timeouted. You should always call `rows.Close` ASAP, but if you \nexperience random `Break`s, remember this warning!\n\n\n## Contribute\n\nJust as with other Go projects, you don't want to change the import paths, but you can hack on the library\nin place, just set up different remotes:\n\n```bash\ncd $GOPATH/src/github.com/godror/godror\ngit remote add upstream https://github.com/godror/godror.git\ngit fetch upstream\ngit checkout -b master upstream/master\n\ngit checkout -f master\ngit pull upstream master\ngit remote add fork git@github.com:mygithubacc/godror\ngit checkout -b newfeature upstream/master\n```\n\nChange, experiment as you wish.  Then run\n\n```bash\ngit commit -m 'my great changes' *.go\ngit push fork newfeature\n```\n\nand you're ready to send a GitHub Pull Request from the\n`github.com/mygithubacc/godror` branch called `newfeature`.\n\n### Pre-commit\n\nDownload a [staticcheck](https://staticcheck.io)\n[release](https://github.com/dominikh/go-tools/releases) and add this to\n.git/hooks/pre-commit:\n\n```bash\n#!/bin/sh\nset -e\n\noutput=\"$(gofmt -l \"$@\")\"\n\nif [ -n \"$output\" ]; then\n    echo \u003e\u00262 \"Go files must be formatted with gofmt. Please run:\"\n    for f in $output; do\n        echo \u003e\u00262 \"  gofmt -w $PWD/$f\"\n    done\n    exit 1\nfi\n\ngo run ./check\nexec staticcheck\n```\n\n### Guidelines\nAs ODPI stores the error buffer in a thread-local-storage, we must ensure that the \nerror is retrieved on the same thread as the prvious function executed on.\n\nThis means we have to encapsulate each execute-then-retrieve-error sequence in\n`runtime.LockOSThread()` and `runtime.UnlockOSThread()`.\nFor details, see [#120](https://github.com/godror/godror/issues/120).\n\nThis is automatically detected by [go run ./check](./check/check.go) which should be called \nin the pre-commit hook.\n\n# Third-party\n\n* [oracall](https://github.com/tgulacsi/oracall) generates a server for calling stored procedures.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodror%2Fgodror","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgodror%2Fgodror","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodror%2Fgodror/lists"}