Giter VIP home page Giter VIP logo

go-ora's Introduction

go-ora

Pure go oracle client

note:

the original oracle drivers are very complex and contain many features which are difficult to add them at one time
your feedbacks are very important for this project to proceed
    - To use version 2 you should import github.com/sijms/go-ora/v2
    - V2 is more preferred for oracle servers 10.2 and above
    - I always update the driver fixing issues and add new features so
      always ensure that you get latest release
    - See examples for more help

Sponsors

JetBrains

How To Use

Connect to Database

  • Simple Connection

    this connection require server name or IP, port, service name, username and password
    • using database/sql
    port := 1521
    connStr := go_ora.BuildUrl("server", port, "service_name", "username", "password", nil)
    conn, err := sql.Open("oracle", connStr)
    // check for error
    err = conn.Ping()
    // check for error
    • using package directly
    port := 1521
    connStr := go_ora.BuildUrl("server", port, "service_name", "username", "password", nil)
    conn, err := go_ora.NewConnection(connStr)
    // check for error
    err = conn.Open()
    // check for error
  • Connect using SID

here we should pass urlOptions note that service name is empty

port := 1521
urlOptions := map[string]string {
  "SID": "SID_VALUE",
}
connStr := go_ora.BuildUrl("server", port, "", "username", "password", urlOptions)
conn, err := sql.Open("oracle", connStr)
// check for error
  • Connect using JDBC string

either pass a urlOption connStr with JDBC string server, port and service name will be collected from JDBC string

urlOptions := map[string]string {
  "connStr": "JDBC string",
}
connStr := go_ora.BuildUrl("", 0, "", "username", "password", urlOptions)
conn, err := sql.Open("oracle", connStr)
// check for error

or use go_ora.BuildJDBC

urlOptions := map[string] string {
	// other options
}
connStr := go_ora.BuildJDBC("username", "password", "JDBC string", urlOptions)
conn, err := sql.Open("oracle", connStr)
// check for error
  • SSL Connection

to use ssl connection you should pass required url options.

port := 2484
urlOptions := map[string] string {
	"ssl": "true", // or enable
	"ssl verify": "false", // stop ssl certificate verification
	"wallet": "path to folder that contains oracle wallet",
}
connStr := go_ora.BuildUrl("server", port, "service_name", "username", "password", urlOptions)
  • OS Auth (for windows)

connect to oracle using OS user instead of oracle user username and password parameters passed empty to BuildUrl see examples/windows_os_auth for more help

urlOptions := map[string]string {
    // optional as it will be automatically set 
	// if you pass an empty oracle user or password
    "AUTH TYPE": "OS",
    // operating system user if empty the driver will use logon user name
    "OS USER": user,
    // operating system password needed for os logon
    "OS PASS": password,
    // Windows system domain name
    "DOMAIN": domain,
	// optional as it will be automatically set 
	// when you define AUTH TYPE=OS in windows
    "AUTH SERV": "NTS",
}
port := 1521
connStr := go_ora.BuildUrl("server", port, "service_name", "", "", urlOptions)
  • Proxy Auth

    if you need to connect with proxy user pass following connection string

    oracle://proxy_user:proxy_password@host:port/service?proxy client name=schema_owner
    
  • Client Auth

    you should have server and client certificate store in wallets + working TCPS communication

    create oracle user as follows:

    CREATE USER "SSLCLIENT" IDENTIFIED EXTERNALLY AS 'CN=ORCLCLIENT';

    configure sqlnet.ora in the server to use client authentication

    SQLNET.AUTHENTICATION_SERVICES=(TCPS,NTS)
    SSL_CLIENT_AUTHENTICATION=TRUE

    connect

    urlOptions := map[string]string {
    "TRACE FILE": "trace.log",
    "AUTH TYPE":  "TCPS",
    "SSL": "enable",
    "SSL VERIFY": "FALSE",
    "WALLET": "PATH TO WALLET"
    }
    connStr := go_ora.BuildUrl("server", 2484, "service", "", "", urlOptions)
  • KERBEROS5 Auth

    note that kerberos need an intact dns system and 3 separate machines to test it

  • kerberos server you can use this link to install on ubuntu

  • oracle server you can configure it from this link

  • client which contain our gocode using package gokrb5

  • Complete code found in examples/kerberos

    urlOptions := map[string]string{
        "AUTH TYPE":  "KERBEROS",
    }
    // note empty password
    connStr := go_ora.BuildUrl("server", 1521, "service", "krb_user", "", urlOptions)
    
    type KerberosAuth struct{}
    func (kerb KerberosAuth) Authenticate(server, service string) ([]byte, error) {
        // see implementation in examples/kerberos
    }
    advanced_nego.SetKerberosAuth(&KerberosAuth{})

before run the code you should run command kinit user

Other Connection Options

  • Define more servers to Connect

urlOptions := map[string]string {
	"server": "server2,server3",
}
connStr := go_ora.BuildUrl("server1", 1251, "service", "username", "password", urlOptions)
/* now the driver will try to connect as follows
1- server1
2- server2
3- server3
*/
  • Client Encryption

this option give the client control weather to use encryption or not

urlOptions := map[string]string {
	// values can be "required", "accepted", "requested", and rejected"
	"encryption": "required",
}
  • Client Data Integrity

this option give the client control weather to user data integrity or not

urlOptions := map[string]string {
    // values can be "required", "accepted", "requested", and rejected"
    "data integrity": "rejected",
}
  • Using Unix Socket

you can use this option if server and client on same linux machine by specify the following url option

urlOptions := map[string]string{
	// change the value according to your machine 
	"unix socket": "/usr/tmp/.oracle/sEXTPROC1",
}
  • Using Timeout

    • activate global timeout value (default=120 sec) to protect against block read/write if no timeout context specified
    • timeout value should be numeric string which represent number of seconds that should pass before operation finish or canceled by the driver
    • to disable this option pass 0 value start from v2.7.15
urlOptions := map[string]string {
	"TIMEOUT": "60",
}
  • Using Proxy user

urlOptions := map[string]string {
	"proxy client name": "schema_owner",
}
connStr := go_ora.BuildUrl("server", 1521, "service", "proxy_user", "proxy_password", urlOptions)
  • Define DBA Privilege

    • define dba privilege of the connection
    • default value is NONE
    • using user sys automatically set its value to SYSDBA
urlOptions := map[string]string {
	"dba privilege" : "sysdba", // other values "SYSOPER"
}
  • Define Lob Fetching Mode

    • this option define how lob data will be loaded
    • default value is pre or inline means lob data is send inline with other values
    • other value is post or stream means lob data will be loaded after finish loading other value through a separate network call
urlOptions := map[string]string {
	"lob fetch": "stream",
}
  • Define Client Charset

    • this option will allow controlling string encoding and decoding at client level
    • so using this option you can define a charset for the client that is different from the server
    • client charset will work in the following situation
      • encoding sql text
      • decoding varchar column
      • encoding and decoding varchar parameters
      • encoding and decoding CLOB
    • nvarchar, nclob and server messages are excluded from client charset
urlOptions := map[string]string {
    // you can use also 
    //"charset": "UTF8",
    "client charset": "UTF8",
}
  • Define Client Territory and Language

    • this will control the language of the server messages
urlOptions := map[string]string {
    "language": "PORTUGUESE",
    "territory": "BRAZILIAN",
}
  • Loging

this option used for logging driver work and network data for debugging purpose

urlOptions := map[string]string {
	"trace file": "trace.log",
}

This produce this kind of log:

2020-11-22T07:51:42.8137: Open :(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.10.10)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=xe)(CID=(PROGRAM=C:\Users\Me\bin\hello_ora.exe)(HOST=workstation)(USER=Me))))
2020-11-22T07:51:42.8147: Connect
2020-11-22T07:51:42.8256: 
Write packet:
00000000  00 3a 00 00 01 00 00 00  01 38 01 2c 0c 01 ff ff  |.:.......8.,....|
00000010  ff ff 4f 98 00 00 00 01  00 ea 00 3a 00 00 00 00  |..O........:....|
00000020  04 04 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00                    |..........|

...

2020-11-22T07:51:42.8705: Query:
SELECT * FROM v$version
2020-11-22T07:51:42.8705: 
Write packet:
00000000  00 55 00 00 06 00 00 00  00 00 03 5e 00 02 81 21  |.U.........^...!|
00000010  00 01 01 17 01 01 0d 00  00 00 01 19 01 01 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 01 00 00 00 00 00 53  |...............S|
00000030  45 4c 45 43 54 20 2a 20  46 52 4f 4d 20 76 24 76  |ELECT * FROM v$v|
00000040  65 72 73 69 6f 6e 01 01  00 00 00 00 00 00 01 01  |ersion..........|
00000050  00 00 00 00 00                                    |.....|
2020-11-22T07:51:42.9094: 
Read packet:
00000000  01 a7 00 00 06 00 00 00  00 00 10 17 3f d5 ec 21  |............?..!|
00000010  d5 37 e0 67 cc 0f eb 03  cc c5 d1 d8 78 78 0b 15  |.7.g........xx..|
00000020  0c 21 20 01 50 01 01 51  01 80 00 00 01 50 00 00  |.! .P..Q.....P..|
00000030  00 00 02 03 69 01 01 50  01 06 01 06 06 42 41 4e  |....i..P.....BAN|
00000040  4e 45 52 00 00 00 00 01  07 07 78 78 0b 16 07 34  |NER.......xx...4|
00000050  2b 00 02 1f e8 01 0a 01  0a 00 06 22 01 01 00 01  |+.........."....|
00000060  19 00 00 00 07 49 4f 72  61 63 6c 65 20 44 61 74  |.....IOracle Dat|
00000070  61 62 61 73 65 20 31 31  67 20 45 78 70 72 65 73  |abase 11g Expres|
00000080  73 20 45 64 69 74 69 6f  6e 20 52 65 6c 65 61 73  |s Edition Releas|
00000090  65 20 31 31 2e 32 2e 30  2e 32 2e 30 20 2d 20 36  |e 11.2.0.2.0 - 6|
000000a0  34 62 69 74 20 50 72 6f  64 75 63 74 69 6f 6e 07  |4bit Production.|
000000b0  26 50 4c 2f 53 51 4c 20  52 65 6c 65 61 73 65 20  |&PL/SQL Release |
000000c0  31 31 2e 32 2e 30 2e 32  2e 30 20 2d 20 50 72 6f  |11.2.0.2.0 - Pro|
000000d0  64 75 63 74 69 6f 6e 15  01 01 01 07 1a 43 4f 52  |duction......COR|
000000e0  45 09 31 31 2e 32 2e 30  2e 32 2e 30 09 50 72 6f  |E.11.2.0.2.0.Pro|
000000f0  64 75 63 74 69 6f 6e 15  01 01 01 07 2e 54 4e 53  |duction......TNS|
00000100  20 66 6f 72 20 4c 69 6e  75 78 3a 20 56 65 72 73  | for Linux: Vers|
00000110  69 6f 6e 20 31 31 2e 32  2e 30 2e 32 2e 30 20 2d  |ion 11.2.0.2.0 -|
00000120  20 50 72 6f 64 75 63 74  69 6f 6e 15 01 01 01 07  | Production.....|
00000130  26 4e 4c 53 52 54 4c 20  56 65 72 73 69 6f 6e 20  |&NLSRTL Version |
00000140  31 31 2e 32 2e 30 2e 32  2e 30 20 2d 20 50 72 6f  |11.2.0.2.0 - Pro|
00000150  64 75 63 74 69 6f 6e 08  01 06 03 14 97 b7 00 01  |duction.........|
00000160  01 01 02 00 00 00 00 00  04 01 05 01 07 01 05 02  |................|
00000170  05 7b 00 00 01 01 00 03  00 01 20 00 00 00 00 00  |.{........ .....|
00000180  00 00 00 00 00 00 00 01  01 00 00 00 00 19 4f 52  |..............OR|
00000190  41 2d 30 31 34 30 33 3a  20 6e 6f 20 64 61 74 61  |A-01403: no data|
000001a0  20 66 6f 75 6e 64 0a                              | found.|
2020-11-22T07:51:42.9104: Summary: RetCode:1403, Error Message:"ORA-01403: no data found\n"
2020-11-22T07:51:42.9104: Row 0
2020-11-22T07:51:42.9104:   BANNER              : Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
2020-11-22T07:51:42.9104: Row 1
2020-11-22T07:51:42.9104:   BANNER              : PL/SQL Release 11.2.0.2.0 - Production
2020-11-22T07:51:42.9104: Row 2
2020-11-22T07:51:42.9104:   BANNER              : CORE	11.2.0.2.0	Production
2020-11-22T07:51:42.9104: Row 3
2020-11-22T07:51:42.9104:   BANNER              : TNS for Linux: Version 11.2.0.2.0 - Production
2020-11-22T07:51:42.9104: Row 4
2020-11-22T07:51:42.9104:   BANNER              : NLSRTL Version 11.2.0.2.0 - Production
2020-11-22T07:51:42.9114: 
  • CID

use this option if you want to pass your own CID started from v2.7.15

default CID

FulCid := "(CID=(PROGRAM=" + op.ProgramPath + ")(HOST=" + op.HostName + ")(USER=" + op.UserName + "))" 

Execute SQL

  • simple query

execute a query follows standards that defined in go package database/sql you have Query used for query rows and Exec used for DML/DDL and PL/SQL

Exec example

// note no semicolon at the end
_, err := conn.Exec(`CREATE TABLE TABLE1(
ID number(10),
NAME varchar2(50),
DAT DATE
)`)
// check for errors

query example:

rows, err := conn.Query("SELECT ID, NAME, DAT FROM TABLE1")
// check for errors
defer rows.Close()
var (
	id int64
	name sql.NullString
	date sql.NullTime
)
for rows.Next() {
	err = rows.Scan(&id, &name, &date)
	// check for errors
}

PL/SQL

// note semicolon at the end
_, err := conn.Exec("begin DBMS_LOCK.sleep(7); end;")
// check for errors

complete example found in examples/crud

  • input parameters

    • parameters in oracle should start with : for example :pr1

passing input parameters as defined by database/sql package.

parameter type

  • int64 / float64 and their equivalent
  • string
  • time.Time
  • any type that support Valuer interface
  • NVarChar
  • TimeStamp
  • TimeStampTZ
  • sql.Null* and go_ora.Null* for all the above
  • Clob, NClob and Blob
  • output parameters

    • passing parameter to Exec to return a value.
    • output parameter should be passed as pointers.
    • all output parameter should be passed inside go_ora.Out or sql.Out structures
    • output parameters like strings should be passed in go_ora.Out to define max size.
var(
	id int64
	name sql.NullString
	date sql.NullTime
)
_, err := conn.Exec("SELECT ID, NAME, DAT INTO :pr1, :pr2, :pr3 FROM TABLE1 WHERE ID=:pr4",
	sql.Out{Dest: &id},
	go_ora.Out{Dest: &name, Size: 100},
	go_ora.Out{Dest: &date},
	1)
  • Lob Types

    • Blob, Clob and NClob
    • Clob use database charset and NClob use database ncharset for string encoding and decoding
    • complete code is found in examples/clob

input parameters

var1 := go_ora.Clob{String: "large string value"}
var2 := go_ora.Blob{Data: []byte("large []byte value")}
_, err := conn.Exec("insert into tb values(:1, :2)", var1, var2)

output parameters

var {
	var1 go_ora.NClob
	var2 go_ora.Blob
}
// set size according to size of your data
_, err := conn.Exec("BEGIN SELECT col1, col2 into :1, :2 FROM tb; END;",
	go_ora.Out{Dest: &var1, size: 100000},
	go_ora.Out{Dest: &var2, size: 300000})
  • BFile (v2.7.23)

    • BFile require oracle directory object name + file name
    • create new BFile object by calling CreateBFile, CreateBFile2 or CreateNullBFile
    • CreateBFile create BFile using *sql.DB while CreateBFile2 take *go_ora.Connection
    • to create null BFile call CreateNullBFile or create object with valid=false
    • you can read BFile value from database either by Query or Exec (output par) using *BFile object
    • You can use object functions after creation or read from database, but you should test for null first
    • BFile functions:
      • Open: will open the file (file object returned from database unopened)
      • Exists: check if the file exists
      • GetLength: return file length
      • Read: read entire file content
      • ReadFromPos: start read from specific position till end of the file
      • ReadBytesFromPos: read portion of the file
      • Close: close file
      • IsOpen: check if the file opened
      • GetDirName: return directory object name
      • GetFileName: return file name
    • complete code for BFile found in examples/bfile
  • Named Parameters

    • to use named parameters just wrap all you parameters inside sql.Named
    • if one of the parameters doesn't have name driver will switch to positional mode
    • parameter named :pr1 in sql should be passed as sql.Named("pr1", 1)
    • Named parameter is useful if you have one value passed in sql multiple times.
    • order is not important
    • complete code for named parameters found in examples/named_pars
  • structures with tag

you can pass a structure parameter to sql in one of the following situation

  • structure that implement Valuer interface
  • oracle user defined type UDT
  • struct with tag db

data in db tag can be recognized by its position or as key=value

type TEMP_TABLE struct {
  // tag by position: db:"name,type,size,direction"
  Id int  `db: "ID,number"`

  Name string `db:"type=varchar,name=NAME"`
}  

struct with tag uses named parameters so you should pass at least the name of the parameter to use this feature.

Type is important in some situations for example if you have field with type time.Time and you want to pass timestamp to database so put type=timestamp

type can be one of the following

number      mapped to golang types integer, float, string, bool
varchar     mapped to any golang types that can converted to string
nvarchar    mapped to any golang types that can converted to string
date        mapped to golang types time.Time and string
timestamp   mapped to golang types time.Time and string
timestamptz mapped to golang types time.Time and string
raw         mapped to golang types []byte and string
blob        mapped to golang types []byte and string
clob        mapped to any golang types that can converted to string
nclob       mapped to any golang types that can converted to string

size and direction are required if the fields mapped to an output parameter

complete code can be found in examples/struct_par

  • Arrays

passing array as a parameter is useful in the following situations

Bulk insert/merge will be activated when you passing all parameters as arrays of same size.

you can also pass an array of tagged structure to do same thing. complete code for bulk-insert/merge can be found in examples/merge

  • Oracle Objects (user defined types)

  • Created inside oracle using create type
  • objects are mapped to golang struct type defined with tag udt followed by field name.
 type Customer struct {
   ID int `udt:"ID"`
   Name string `udt:"NAME"`
}
  • each object should register with go_ora.RegisterType or go_ora.RegisterTypeWithOwner passing typeName, arrayTypeName (for that type or empty) and empty instance of struct
  • driver support nested type start from (v2.8.5)
  • for array of regular type (v2.8.7) pass regular type name, arrayTypeName and nil for object instance
  • regular type supported
    • number
    • varchar2
    • nvarchar2
    • date
    • timestamp
    • timestamp with local time zone
    • RAW
    • BLOB
    • CLOB
    • NCLOB
  • to pass oracle object as a parameter efficiently use go_ora.Object{Owner: owner, Name: name, Value: val}
  • regular type array should be passed wrapped inside go_ora.Object otherwise it will be interpreted as associative array
  • complete code is found in
  • RefCursor

as an output parameter

  var cursor go_ora.RefCursor
  _, err = conn.Exec(`BEGIN PROC1(:1, :2); END;`, 1, sql.Out{Dest: &cursor})

you can use go_ora.WrapRefCursor(...) to convert *RefCursor into *sql.Rows started from v2.7.17

complete code for RefCursor as output parameter found in examples/refcursor

Map RefCursor to sql.Rows

// TEMP_FUNC_316 is sql function that return RefCursor
sqlText := `SELECT TEMP_FUNC_316(10) from dual`

// use Query and don't use QueryRow
rows, err := conn.Query(sqlText)
if err != nil {
	return err
}

// closing the parent rows will automatically close cursor
defer rows.Close()

for rows.Next() {
    var cursor sql.Rows
	err = rows.Scan(&cursor)
	if err != nil {
		return err
	}
	var (
        id   int64
        name string
        val  float64
        date time.Time
    )
	
    // reading operation should be inside rows.Next
    for cursor.Next() {
        err = cursor.Scan(&id, &name, &val, &date)
        if err != nil {
            return err
        }
        fmt.Println("ID: ", id, "\tName: ", name, "\tval: ", val, "\tDate: ", date)
    }
}

complete code for mapping refcursor to sql.Rows is found in example/refcursor_to_rows

  • Connect to multiple database

    • note that sql.Open(...) will use default driver so it will be suitable for one database projects.
    • to use multiple database you should create a separate driver for each one (don't use default driver)
  // Get a driver-specific connector.   
  connector, err := go_ora.NewConnector(connStr)
  if err != nil {
    log.Fatal(err)
  }

  // Get a database handle.
  db = sql.OpenDB(connector)
  • use custom configurations for connection

    • another way to set connection configuration instead of using connection string (DSN)
    • for custom dial you should implement DialerContext interface or simply use config.RegisterDial function (start from v2.8.19)
    • example code:
config, err := go_ora.ParseConfig(DSN)
	
// for using custom dial use RegisterDial
// start from v2.8.19
config.RegisterDial(func(ctx context.Context, network, address string) (net.Conn, error) {
    // your custom dial code
})

// modify config structure 

go_ora.RegisterConnConfig(config)
// now open db note empty DSN 
db, err := sql.Open("oracle", "")
  • Use Custom String encode/decode

    • if your database charset is not supported you can create a custom object that implement IStringConverter interface and pass it to the driver as follows
  db, err := sql.Open("oracle", connStr)
  if err != nil {
	  // error handling
  }
  
  // call SetStringConverter before use db object
  // charset and nCharset are custom object that implement 
  // IStringConverter interface
  // if you pass nil for any of them then the driver will use 
  // default StringConverter
  go_ora.SetStringConverter(db, charset, nCharset)
  
  // rest of your code
  • Session Parameters

    • you can update session parameter after connection as follow
    db, err := sql.Open("oracle", connStr)
    if err != nil {
      // error handling
    }
    // pass database, key, value
    err = go_ora.AddSessionParameter(db, "nls_language", "english")
    if err != nil {
      // error handling
    }

releases

version 2.8.19

  • add support for long input:

    if input parameter (string or []byte) size is larger than 32Kb the driver will switch to oracle type LongVarchar and LongRaw so now you can input data with size up to 1 GB that fit into LONG and LOB columns

  • long input: example and test
  • add function RegisterDial to the configuration object that accept func input
config, err := go_ora.ParseConfig(`yours DSN string`)
config.RegisterDial(func(ctx context.Context, network, address string) (net.Conn, error) {
    // your custom dial code
})
go_ora.RegisterConfig(config)
db, err := sql.Open("oracle", "")

version 2.8.12

  • add 2 functions
    • ParseConfig
    • RegisterConnConfig
  • fix issue related to LONG and JSON data types
  • fix issue related to using returning clause with prepared statement will hang
  • add lob fetch=inline which is equal to lob fetch=pre
  • complete fix for data race

version 2.8.8

  • introduce new connection break using go-routines thanks to @rheilek
  • return BLOB as longRAW and CLOB,NCLOB as LONG in lob prefetch mode so supported data size increased from 32KB to 1GB
  • fix issue in bulk insert when pass data types
  • add lob fetch=stream which is equal to lob fetch=post
  • testing file prefetch large blob

version 2.8.7

  • add support for regular type array
  • add support for nested null object and array
  • introduce new type go_ora.Object{Owner: owner, Name: name, Value: val} for passing input/output oracle objects
  • fix issue int is truncate to 9223372036854775807 for larger values
  • fix issue loss of time fraction in timestamp

version 2.8.6

  • add support for nested user define type (UDT) array.
  • add testing file (TestIssue/nested_udt_array_test.go) with 2 level nesting
  • fix issue related to date with time zone which occur with some oracle servers
  • correct reading of oracle date with local time zone as output col/par.
  • more testing is done for oracle date/time types now you can pass time.Time{} as input/output for oracle date/time types except:
    • associative array which require strict oracle type
  • add testing file (TestIssue/time_test.go)

version 2.8.5

  • add support for nested user defined types (UDT)
  • add test file for nested UDT
  • fix issue related to passing time with timezone as default input parameter for DATE, TIMESTAMP, TIMESTAMP with timezone now user should define which type will be used according to oracle data type
go type oracle type
time.Time DATE
go_ora.TimeStamp TIMESTAMP
go_ora.TimeStampTZ TIMESTAMP WITH TIME ZONE
  • fix issue related to returning clause

version 2.8.4

  • fix regression occur with custom types that support valuer and scanner interfaces
  • fix regression occur with struct par that contain pointer (output)
  • fix issue related to struct pars contain LOBs
  • add DelSessionParam to remove session parameters when it is not needed
  • add messageSize for Dequeue function in dbms.AQ
  • add tests for module, features and issues

version 2.8.2

  • now most of charsets are supported. still some of them are not fully tested.
  • fix issue related to nested pointers

version 2.8.0

  • use buffered input during network read to avoid network data loss (occur with slow connections).
  • fix charset mapping for charset id 846.
  • add support for charset id 840
  • re-code timeouts and connection break to get clean non-panic exit when context is timout and operation is cancelled

version 2.7.25

  • Add feature that enable the driver to read oracle 23c wallet
  • introduce passing time.Time{} as input parameter for DATE, TIMESTAMP and TIMESTAMP WITH TIMEZONE data types note still output parameters need these types
  • other bug fixes

version 2.7.23

  • Update BFile code to support null value and use *sql.DB
  • Fix issue: BFile not working with lob pre-fetch mode
  • Improve Bulk insert by removing un-necessary calls for EncodeValue so Bulk insert now can support Lob objects
  • Fix issue related to refcursor

version 2.7.20

  • fix time not in timezone issue specially with oracle 19c
  • add function to set value for session parameters that will be applied for subsequent connections
  • fix issue #461
  • bug fixes and improvements

version 2.7.18

  • Add 2 function go_ora.NewDriver and go_ora.NewConnector
  • Add new function go_ora.SetStringConverter which accept custom converter for unsupported charset and nCharset
  • go_ora.SetStringConverter accept *sql.DB as first parameter and IStringConveter interface object for charset and nCharset (you can pass nil to use default converter)
  • Add support for charset ID 846

version 2.7.17

  • add WrapRefCursor which converts *RefCursor into *sql.Rows
  • code:
// conn is *sql.DB
// cursor comming from output parameter
rows, err := go_ora.WrapRefCursor(context.Background(), conn, cursor)

version 2.7.11

  • add support for DBMS_OUTPUT
import (
  "database/sql"
  db_out "github.com/sijms/go-ora/dbms_output"
  _ "github.com/sijms/go-ora/v2"
  "os"
)

// create new output
// conn is *sql.DB
// bufferSize between 2000 and 32767
output, err := db_out.NewOutput(conn, 0x7FFF)

// close before exit
defer func() {
  err = output.Close()
}()

// put some line 
err = exec_simple_stmt(conn, `BEGIN
DBMS_OUTPUT.PUT_LINE('this is a test');
END;`)

// get data as string
line, err := output.GetOutput()

// or print it to io.StringWriter
err = output.Print(os.Stdout)
  • complete code found in examples/dbms_output/main.go

version 2.7.7:

  • add support for CLOB/BLOB in UDT
  • add support for UDT array as output parameters
  • add function go-ora.RegisterType(...) so you can use it with database/sql package
  • add arrayTypeName (input for array type can be empty) to RegisterType(...) to support UDT array
  • examples/udt_array contain complete code that explain how to use udt array
  • parameter encode/decode is recoded from the start
  • fix uint64 truncation
  • fix some other issue

version 2.7.4:

  • activate global timeout value to protect against block read/write if no timeout context specified
  • default value for timeout is 120 second you can change by passing one of the following ["TIMEOUT", "CONNECT TIMEOUT", "CONNECTION TIMEOUT"]
  • other feature/issues:
    • fix passing empty []byte{} will produce error
    • fix passing empty array as a parameter will produce error
    • return first binding error when the driver return ora-24381: error in DML array

version 2.7.3: Use database/sql fail over

  • use database/sql fail over by returning driver.ErrBadConn when connection interrupted
  • other features:
    • add support for RC4 encryption

version 2.7.2: Use golang structure as an oracle (output) parameters

all rules used for input will be required for output plus:

  • structure should be passed as a pointer
  • tag direction is required to be output or inout. size is used with some types like strings
  • each field will be translated to a parameter as follows
number      mapped to sql.NullFloat64
varchar     mapped to sql.NullString
nvarchar    mapped to sql.NullNVarchar
date        mapped to sql.NullTime
timestamp   mapped to NullTimeStamp
timestamptz mapped to NullTimeStampTZ
raw         mapped to []byte
clob        mapped to Clob
nclob       mapped to NClob
blob        mapped to Blob

all fields that support driver.Valuer interface will be passed as it is

  • data assigned back to structure fields after exec finish when a null value read then field value will set to reflect.Zero
  • examples/struct_pars/main.go contain full example for reading and writing struct pars

version 2.7.1: Use golang structure as an oracle (input) parameters

  • by define structure tag db now you can pass information to sql.Exec
  • data in db tag can be recognized by its position or as key=value
type TEMP_TABLE struct {
	// tag by position: db:"name,type,size,direction"
	Id    int      `db:"ID,number"`
	// tag as key=value: db:"size=size,name=name,dir=directiontype=type"
	Name  string   `db:"type=varchar,name=NAME"`
}
  • you should pass at least the name of the parameter to use this feature
  • input parameters need only name and type. if you omit type driver will use field value directly as input parameter. type is used to make some flexibility example use time.Time field and pass type=timestamp in this case timestamp will be used instead of default value for time.Time which is date
  • type can be one of the following:
number      mapped to golang types integer, float, string, bool
varchar     mapped to any golang types that can converted to string
nvarchar    mapped to any golang types that can converted to string
date        mapped to golang types time.Time and string
timestamp   mapped to golang types time.Time and string
timestamptz mapped to golang types time.Time and string
raw         mapped to golang types []byte and string
blob        mapped to golang types []byte and string
clob        mapped to any golang types that can converted to string
nclob       mapped to any golang types that can converted to string
  • other features:
    • tag for user defined type UDT changed from oracle to udt
    • add 2 url options give the client control weather to use encryption, data integrity or not
    urlOptions := map[string]string {
      // values can be "required", "accepted", "requested", and rejected"
      "encryption": "required",
      "data integrity": "rejected",
    }
    • fix issue #350

version 2.6.17: Implement Bulk(Insert/Merge) in ExecContext

  • now you can make bulk (insert/merge) with sql driver Exec as follows:
    • declare sql text with Insert or Merge
    • pass all parameter as array
    • number of rows inserted will equal to the least array size
  • Named parameter is also supported
  • full code is present in examples/merge

version 2.6.16: Map RefCursor to sql.Rows

  • mapping RefCursor to sql.Rows will work with select/scan.
// TEMP_FUNC_316 is sql function that return RefCursor
sqlText := `SELECT TEMP_FUNC_316(10) from dual`

// use Query and don't use QueryRow
rows, err := conn.Query(sqlText)
if err != nil {
	return err
}

// closing the parent rows will automatically close cursor
defer rows.Close()

for rows.Next() {
    var cursor sql.Rows
	err = rows.Scan(&cursor)
	if err != nil {
		return err
	}
	var (
        id   int64
        name string
        val  float64
        date time.Time
    )
	
    // reading operation should be inside rows.Next
    for cursor.Next() {
        err = cursor.Scan(&id, &name, &val, &date)
        if err != nil {
            return err
        }
        fmt.Println("ID: ", id, "\tName: ", name, "\tval: ", val, "\tDate: ", date)
    }
}
  • complete code is present in examples/refcursor_to_rows/main.go

version 2.6.14: Add Support for Named Parameters

  • to switch on named parameter mode simply pass all your parameter to Query or Exec as sql.Named("name", Value)
  • if one of the parameter doesn't contain name the driver automatically switch to positional mode
  • parameter name in sql will be for example :pr1 and its value will be sql.Named("pr1", 1)
  • when using named parameters the order of the parameters is not important as the driver will re-arrange the parameter according to declaration in sql text
  • See examples/named_pars/main.go for example code

version 2.6.12: Add Client Charset option

  • this option will allow controlling string encoding and decoding at client level
  • so using this option you can define a charset for the client that is different from the server
  • client charset will work in the following situation
    • encoding sql text
    • decoding varchar column
    • encoding and decoding varchar parameters
    • encoding and decoding CLOB
  • nvarchar, nclob and server messages are excluded from client charset
  • code
urlOptions := map[string]string {
	// you can use also 
	//"charset": "UTF8",
	"client charset": "UTF8",
	"trace file": "trace.log",
}
connStr := go_ora.BuildUrl("server", 1521, "service", "", "", urlOptions)

version 2.6.9: Re-Code Failover

  • now failover start when receive the following error:
    • io.EOF
    • syscall.EPIPE
  • failover added for the following
    • Query
    • Fetch
    • Exec
    • Ping
    • Commit
    • Rollback
    • RefCursor Query
  • In all situation Failover will try to reconnect before returning error except in case of Query failover will reconnect + requery

version 2.6.8: Fix return long data type with lob prefetch option:

  • now you can return up to 0x3FFFFFFF of data from long coumn type
  • examples/long insert 0x3FFF bytes of data into long column and query it again
  • for large data size better use lob fetch=post

version 2.6.5: Add New Url Options (Language and Territory)

  • this will control the language of the server messages
urlOptions := map[string]string {
"language": "PORTUGUESE",
"territory": "BRAZILIAN",
}
url := go_ora.BuildUrl(server, port, service, user, password, urlOptions)

version 2.6.4: Add Support for TimeStamp with timezone

  • now you can use TimeStampTZ as input/output parameters to manage timestamp with timezone
  • see code in examples/timestamp_tz

version 2.6.2: Add Support for Lob Prefetch

  • now you can control how you need to get lob data
    • pre-fetch (default) = lob data is sent from the server before send lob locator
    • post-fetch = lob data is sent from the server after send lob locator (need network call)
  • you can do this using url options
urlOptions := map[string]string {
  "TRACE FILE": "trace.log",
  "LOB FETCH": "PRE", // other value "POST"
}
connStr := go_ora.BuildUrl("server", 1521, "service", "", "", urlOptions)

version 2.5.33: Add Support for Client Authentication

  • you should have server and client certificate store in wallets + working TCPS communication
  • create oracle user as follows:
CREATE USER "SSLCLIENT" IDENTIFIED EXTERNALLY AS 'CN=ORCLCLIENT';
  • configure sqlnet.ora in the server to use client authentication
SQLNET.AUTHENTICATION_SERVICES=(TCPS,NTS)
SSL_CLIENT_AUTHENTICATION=TRUE
  • now connect
urlOptions := map[string]string {
  "TRACE FILE": "trace.log",
  "AUTH TYPE":  "TCPS",
  "SSL": "TRUE",
  "SSL VERIFY": "FALSE",
  "WALLET": "PATH TO WALLET"
}
connStr := go_ora.BuildUrl("server", 2484, "service", "", "", urlOptions)

version 2.5.31: Add BulkCopy using DirectPath (experimental)

  • it is a way to insert large amount of rows in table or view
  • this feature use oracle direct path
  • this feature still not implemented for the following types:
    • LONG
    • CLOB
    • BLOB
  • for more help about using this feature return to bulk_copy example

version 2.5.19: Add Support for Kerberos5 Authentication

  • note that kerberos need an intact dns system
  • to test kerberos you need 3 machine
  • there is an example code for kerberos, but you need to call kinit user before using the example
urlOptions := map[string]string{
    "TRACE FILE": "trace.log",
    "AUTH TYPE":  "KERBEROS",
}
// note empty password
connStr := go_ora.BuildUrl("server", 1521, "service", "krb_user", "", urlOptions)

type KerberosAuth struct{}
func (kerb KerberosAuth) Authenticate(server, service string) ([]byte, error) {
    // see implementation in examples/kerberos
}
advanced_nego.SetKerberosAuth(&KerberosAuth{})

version 2.5.16: Add Support for cwallet.sso created with -auto_login_local option

  • note that this type of oracle wallets only work on the machine where they were created

version 2.5.14: Failover and wallet update

  • Exec will return error after connection restore
  • add new field WALLET PASSWORD to read ewallet.p12 file

version 2.5.13: Add Support For Failover (Experimental)

  • to use failover pass it into connection string as follow
urlOptions := map[string]string{
	"FAILOVER": "5",
	"TRACE FILE": "trace.log",
}
databaseUrl := go_ora.BuildUrl(server, port, service, user, password, urlOptions)
  • FAILOVER value is integer indicate how many times the driver will try to reconnect after lose connection default value = 0
  • failover will activated when stmt receive io.EOF error during read or write
  • FAILOVER work in 3 places:
    • Query when fail the driver will reconnect and re-query up to failover number.
    • Exec when fail the driver will reconnect up to failover times then return the error to avoid unintended re-execution.
    • Fetch when fail the driver will reconnect up to failover times then return the error (whatever failover success or fail)

version 2.4.28: Binary Double And Float Fix

  • Now you can read binary double and float without error issue#217
  • You can avoid calling cgo function user.Current() if you define environmental variable $USER

version 2.4.20: Query To Struct

  • you can query to struct that contain basic types (int, float, string, datetime) or any types that implement sql.Scanner interface
  • see query to struct example for more information

version 2.4.18: Add support for proxy user

if you need to connect with proxy user pass following connection string

oracle://proxy_user:proxy_password@host:port/service?proxy client name=schema_owner

version 2.4.8: JDBC connect string

  • Add new function go_ora.BuildJDBC
    // program will extract server, ports and protocol and build
    // connection table
    connStr := `(DESCRIPTION=
    (ADDRESS_LIST=
    	(LOAD_BALANCE=OFF)
        (FAILOVER=ON)
    	(address=(PROTOCOL=tcps)(host=localhost)(PORT=2484))
    	(address=(protocol=tcp)(host=localhost)(port=1521))
    )
    (CONNECT_DATA=
    	(SERVICE_NAME=service)
        (SERVER=DEDICATED)
    )
    (SOURCE_ROUTE=yes)
    )`
    // use urlOption to set other options like:
    // TRACE FILE = for debug
    // note SSL automatically set from connStr (address=...
    // SSL Verify = need to cancel certifiate verification
    // wallet path
    databaseUrl := go_ora.BuildJDBC(user, password, connStr, urlOptions)
    conn, err := sql.Open("oracle", databaseUrl)
	if err != nil {
		fmt.Println(err)
		return
	}
    err = conn.Ping()
	if err != nil {
		fmt.Println(err)
		return
	}

version 2.4.5: Support BFile

  • connect as sys and create directory object that refer to physical directory
  • grant read,write on directory 'dirName' to user
  • put text file in the directory with name = fileName
// create and open connection before use BFile
conn, err := go_ora.NewConnection(connStr)
// check for error
err = conn.Open()
// check for error
defer conn.Close()

// Create BFile object
file, err := go_ora.BFile(conn, dirName, fileName)
// check for error

// before use BFile it must be opened
err = file.Open()
// check for error
defer file.Close()

// does the file exist
exists, err := file.Exists()
// check for error

if exists {
    length, err := file.GetLength()
    // check for error
    
    // read all data
    data, err := file.Read()
    
    // read at position 2
    data, err = file.ReadFromPos(2)
    
    // read 5 bytes count start at position 2
    data, err = file.ReadBytesFromPos(2, 5)
  • you can pass BFile object as input parameter or receive it from query or output parameters for more detail see example bfile

version 2.4.4: Support for unix socket IPC

you can use this option if server and client on same linux machine by specify the following url option

urlOptions := map[string]string{
	// change the value according to your machine
	"unix socket": "/usr/tmp/.oracle/sEXTPROC1"
}

version 2.4.3: Input Parameter CLOB and BLOB Accept Large Data Size

you can pass input CLOB and BLOB with any data size up to data type limit

version 2.4.1: Add support for connection time out + context read and write

you can determine connection overall lifetime through url options

// set connection time for 3 second
urlOptions := map[string]string {
    "CONNECTION TIMEOUT": "3"
}
databaseUrl := go_ora.BuildUrl(server, port, service, user, password, urlOptions)

see context example for more help about using context

version 2.4.0: Add support for Arrays

  • add support for oracle associative array as input and output parameter type
  • add BulkInsert function which dramatically improve performance (> 10x) during insert
  • add support for nullable type in DataSet.Scan function
  • Bug fixes
  • examples (bulk_insert and arrays) contain explanation of use of this 2 major features
// sqlText: sql text with parameters
// rowNum: number of rows to insert
// columns: each column contain array of driver.Value size of column should
//          equal to rowNum
func (conn *Connection) BulkInsert(sqlText string, rowNum int, columns ...[]driver.Value) (*QueryResult, error) 

version 2.3.5: Add support for OS Auth (Windows) With Password Hash

now you can pass password hash of the user instead of real password

source of hash:

  • windows registry
  • create the hash by md4(unicode(password)) passing hash through url option as follow
urlOptions := map[string]string {
	"OS HASH": "yourpasswordhash"
	// or
	"OS PassHash": "yourpasswordhash"
	// or
	"OS Password Hash": "yourpasswordhash"
}

note:

you can use NTSAuthInterface

type YourCustomNTSManager struct {
	NTSAuthDefault
}
func (nts *NTSAuthHash) ProcessChallenge(chaMsgData []byte, user, password string) ([]byte, error) {
    // password = get (extract) password hash from Windows registry
	return ntlmssp.ProcessChallengeWithHash(chaMsgData, user, password)
}
// now you can pass empty user and password to the driver

version 2.3.3: Add support for OS Auth (Windows)

you can see windows_os_auth example for more detail

  • NTS packets are supplied from the following github package: go-ntlmssp
  • empty username or password will suppose OS Auth by default
  • AUTH TYPE: "OS" optional
  • OS USER optional if omit the client will use logon user
  • OS PASS is obligatory to make OS Auth using NTS
  • DOMAIN optional for windows domain
  • AUTH SERV: "NTS" optional as NTS is automatically added if the client running on Windows machine
  • DBA PRIVILEGE: "SYSDBA" optional if you need a SYSDBA access
urlOptions := map[string]string{
    // automatically set if you pass an empty oracle user or password
    // otherwise you need to set it
    "AUTH TYPE": "OS",
    // operating system user if empty the driver will use logon user name
    "OS USER": user,
    // operating system password needed for os logon
     "OS PASS": password,
    // Windows system domain name
    "DOMAIN": domain,
    // NTS is the required for Windows os authentication
    // when you run the program from Windows machine it will be added automatically
    // otherwise you need to specify it
    "AUTH SERV": "NTS",
    // uncomment this option for debugging
    "TRACE FILE": "trace.log",
}
databaseUrl := go_ora.BuildUrl(server, port, service, "", "", urlOptions)

note (Remote OS Auth):

  • you can make OS Auth on the same machine (Windows Server) or different machine (Windows Server) and (Other Client) and in this situation you need to pass AUTH SERV: "NTS" as url parameter

note (advanced users):

  • You can use custom NTS auth manager by implementing the following interface
type NTSAuthInterface interface {
	NewNegotiateMessage(domain, machine string) ([]byte, error)
	ProcessChallenge(chaMsgData []byte, user, password string) ([]byte, error)
}
  • set newNTS auth manager before open the connection
go_ora.SetNTSAuth(newNTSManager)
  • advantage of custom manager: you may not need to provide OS Password. for example using .NET or Windows API code as original driver
// CustomStream will take data from NegotiateStream and give it to the driver
// through NewNegotiateMessage
// Then take data form the driver (Challenge Message) to NegotiateStream
// And return back Authentication msg to the driver through ProcessChallenge
// as you see here CredentialCache.DefaultNetworkCredentials will take auth data
// (username and password) from logon user
new NegotiateStream(new YourCustomStream(), true).AuthenticateAsClient(CredentialCache.DefaultNetworkCredentials, "", ProtectionLevel.None, TokenImpersonationLevel.Identification);

version 2.3.1: Fix issue related to use ipv6

now you can define url that contain ipv6

url := go_ora.BuildUrl("::1", 1521, "service", "user", "password", nil)
url = "oracle://user:password@[::1]:1521/service"

version 2.3.0: Add support for Nullable types

  • support for nullable type in output parameters
  • add more nullable type NullTimeStamp and NullNVarChar

version 2.2.25: Add support for User Defined Type (UDT) as input and output parameter

  • see example udt_pars for more help

version 2.2.23: User Defined Type (UDT) as input parameters

  • Add support for UDT as input parameter
  • Add go_ora.Out struct with Size member to set output parameter size

version 2.2.22: Lob for output parameters

  • Add new types for output parameter which is go_ora.Clob and go_ora.Blob used for receiving Clob and Blob from output parameters see clob example for more details
  • Fix some issue related to reading output parameters
  • Fix issue related to reading user defined type UDT

version 2.2.19: improve lob reading with high prefetch rows value

  • Now Prefetch rows value is automatically calculated (when left with its default value = 25) according to column size
  • Reading lob is retarded until all record has been read this fix error happen when you try to read lob with large PREFETCH_ROWS value

version 2.2.9: add support for connect to multiple servers

define multiple server in 2 way

  • in url string options
// using url options
databaseURL := "oracle://user:pass@server1/service?server=server2&server=server3"
/* now the driver will try connection as follow
1- server1
2- server2
3- server3
*/
  • using BuildUrl function
urlOptions := map[string] string {
    "TRACE FILE": "trace.log",
    "SERVER": "server2, server3",
    "PREFETCH_ROWS": "500",
    //"SSL": "enable",
    //"SSL Verify": "false",
}
databaseURL := go_ora.BuildUrl(server1, 1521, "service", "user", "pass", urlOptions)

version 2.2.8: add OracleError class

OracleError carry error message from the server

version 2.2.7: Add support for user defined types

  • this feature is now tested against these oracle versions 10.2, 12.2, 19.3.
  • RegisterType function need extra parameter owner (oracle user who create the type).

version 2.2.6 (pre-release - experimental): Add support for user defined types

to use make the following (oracle 12c)

  • define custom type in the oracle
create or replace TYPE TEST_TYPE1 IS OBJECT 
( 
    TEST_ID NUMBER(6, 0),
    TEST_NAME VARCHAR2(10)
)
  • define struct in go with tag
type test1 struct {
    // note use int64 not int
    // all tagged fields should be exported 
    // tag name:field_name --> case insensitive
    Id int64       `oracle:"name:test_id"`
    Name string    `oracle:"name:test_name"`
}
  • connect to database
databaseURL := go_ora.BuildUrl("localhost", 1521, "service", "user", "pass", nil)
conn, err := sql.Open("oracle", databaseURL)
// check for err
err = conn.Ping()
// check for err
defer func() {
    err := conn.Close()
    // check for err
}()
  • register type
if drv, ok := conn.Driver().(*go_ora.OracleDriver); ok {
    err = drv.Conn.RegisterType("owner", "TEST_TYPE1", test1{})
    // check for err
}
  • select and display data
rows, err := conn.Query("SELECT test_type1(10, 'test') from dual")
// check for err
var test test1
for rows.Next() {
    err = rows.Scan(&test)
    // check for err
    fmt.Println(test)
}

version 2.2.5

  • add function go_ora.BuildUrl to escape special characters

version 2.2.4

  • add support for tcps. you can enable tcps through the following url options
  • this link explain how to enable tcps in your server
wallet=wallet_dir // wallet should contain server and client certificates
SSL=true          // true or enabled
SSL Verify=false  // to bypass certificate verification

version 2.1.23

  • now support auto-login oracle wallet (non-local)
  • note: to use wallet you need to specify directory path for wallet the directory should contain cwallet.sso file "the file that will be used"
sqlQuery := "oracle://[email protected]:1522/service"
sqlQuery += "?TRACE FILE=trace.log"
sqlQuery += "&wallet=path_to_wallet_directory"
conn, err := sql.open("oracle", sqlQuery)
server:port/service ---> should be supplied when using wallet
user ---> is optional when omitted the reader will return first matched dsn
password ---> should be empty as it will be supplied from wallet

version 2.1.22

  • now support data packet integrity check using MD5, SHA1, SHA256, SHA384, SHA512
  • key is exchanged between server and client using Diffie Hellman method
  • note: to enable data integrity check add the following line to sqlnet.ora of the server
# possible values ([accepted | rejected | requested | required])
SQLNET.CRYPTO_CHECKSUM_SERVER = required
# possible values ([MD5 | SHA1 | SHA256 | SHA384 | SHA512])
SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER = SHA512

version 2.1.21

  • now support data packet encryption using AES.
  • key is exchanged between server and client using Diffie Hellman method
  • note: to enable AES encryption add the following line to sqlnet.ora of the server
# possible values ([accepted | rejected | requested | required])
SQLNET.ENCRYPTION_SERVER = required
# possible values for AES (AES256 | AES192 | AES128)
SQLNET.ENCRYPTION_TYPES_SERVER = AES256

version 2.1.20

  • add new type go_ora.NVarChar now you can pass string parameter in 2 way:
ย  ย  1- varchar string:
_, err := conn.Exec(inputSql, "7586")
ย  ย 2- nvarchar string:
_, err := conn.Exec(inputSql, go_ora.NVarChar("7586"))

version 2.1.19

  • support more charsets (0x33D, 0x33E, 0x33F, 0x340, 0x352, 0x353, 0x354)

version 2.0-beta

  • update client version to 317
  • update ttc version to: 9
  • use 4 byte packet length instead of 2 bytes
  • use advanced negotiation
  • use big clear chunks
  • use more verifier type in authentication object

go-ora's People

Contributors

3th1nk avatar almnorth avatar btnguyen2k avatar chalharu avatar drhayt avatar ducknificient avatar falco467 avatar fitlcarlos avatar fupeijiang avatar gorandumic avatar hmmftg avatar howmp avatar jedib0t avatar ljyf5593 avatar lobicode avatar lucasjellema avatar novikovas avatar orangekame3 avatar ranxy avatar rheilek avatar rocksnow1942 avatar sanmarco avatar sijms avatar simulot avatar srtpatil avatar tboudalier avatar thehaung avatar wes-pro avatar wilkice avatar zafhiel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-ora's Issues

Getting error ORA-01882

Hi,
I am getting the error "ORA-01882: timezone region not found" when I try to stablish a connection to Oracle server (12c)
Using latest go (1.15) on linux.

Any idea?

Thanks!!!

UNICODE NVARCHAR2 fields aren't decoded as UTF-8

I have done a small CLI query tool to ease some tests.

The db I'm testing uses UNICODE as char set, and I get UNICODE encoded string. See the screen capture:
image

In the "golang" way, foreign strings would be converted into utf-8 and back. Doing like this would ease the work in the client application.

I suppose this easily done for UNICODE or Windows Western char set, but how to manage all others ?
What is your position on this?

Cannot Login after last update

Hi All,

After last update, I cannot login to database.

2021-03-08T11:19:16.7189: Open :(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=racazbprd.mch.moc.sgps:1521)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=WMPLA2PP)(CID=(PROGRAM=/tmp/go-build262618597/b001/exe/main)(HOST=rodrigo-bold)(USER=rodrigo))))
2021-03-08T11:19:16.7189: Connect
2021-03-08T11:19:16.7761: 
Write packet:
00000000  01 14 00 00 01 00 00 00  01 3d 01 2c 0c 01 ff ff  |.........=.,....|
00000010  ff ff 4f 98 00 00 00 01  00 ce 00 46 00 00 00 00  |..O........F....|
00000020  01 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 ff ff 00 00  |................|
00000040  ff ff 00 00 00 00 28 44  45 53 43 52 49 50 54 49  |......(DESCRIPTI|
00000050  4f 4e 3d 28 41 44 44 52  45 53 53 3d 28 50 52 4f  |ON=(ADDRESS=(PRO|
00000060  54 4f 43 4f 4c 3d 74 63  70 29 28 48 4f 53 54 3d  |TOCOL=tcp)(HOST=|
00000070  72 61 63 61 7a 62 70 72  64 2e 6d 63 68 2e 6d 6f  |racazbprd.mch.mo|
00000080  63 2e 73 67 70 73 3a 31  35 32 31 29 28 50 4f 52  |c.sgps:1521)(POR|
00000090  54 3d 31 35 32 31 29 29  28 43 4f 4e 4e 45 43 54  |T=1521))(CONNECT|
000000a0  5f 44 41 54 41 3d 28 53  45 52 56 49 43 45 5f 4e  |_DATA=(SERVICE_N|
000000b0  41 4d 45 3d 57 4d 50 4c  41 32 50 50 29 28 43 49  |AME=WMPLA2PP)(CI|
000000c0  44 3d 28 50 52 4f 47 52  41 4d 3d 2f 74 6d 70 2f  |D=(PROGRAM=/tmp/|
000000d0  67 6f 2d 62 75 69 6c 64  32 36 32 36 31 38 35 39  |go-build26261859|
000000e0  37 2f 62 30 30 31 2f 65  78 65 2f 6d 61 69 6e 29  |7/b001/exe/main)|
000000f0  28 48 4f 53 54 3d 72 6f  64 72 69 67 6f 2d 62 6f  |(HOST=rodrigo-bo|
00000100  6c 64 29 28 55 53 45 52  3d 72 6f 64 72 69 67 6f  |ld)(USER=rodrigo|
00000110  29 29 29 29                                       |))))|
2021-03-08T11:19:16.7909: 
Read packet:
00000000  00 0a 00 00 05 02 00 00  01 31                    |.........1|
2021-03-08T11:19:16.7909: 
Read packet:
00000000  01 3b 00 00 06 00 00 00  00 40 28 41 44 44 52 45  |.;.......@(ADDRE|
00000010  53 53 3d 28 50 52 4f 54  4f 43 4f 4c 3d 54 43 50  |SS=(PROTOCOL=TCP|
00000020  29 28 48 4f 53 54 3d 31  30 2e 31 32 37 2e 32 34  |)(HOST=10.127.24|
00000030  35 2e 33 33 29 28 50 4f  52 54 3d 31 35 32 31 29  |5.33)(PORT=1521)|
00000040  29 00 28 44 45 53 43 52  49 50 54 49 4f 4e 3d 28  |).(DESCRIPTION=(|
00000050  41 44 44 52 45 53 53 3d  28 50 52 4f 54 4f 43 4f  |ADDRESS=(PROTOCO|
00000060  4c 3d 74 63 70 29 28 48  4f 53 54 3d 72 61 63 61  |L=tcp)(HOST=raca|
00000070  7a 62 70 72 64 2e 6d 63  68 2e 6d 6f 63 2e 73 67  |zbprd.mch.moc.sg|
00000080  70 73 3a 31 35 32 31 29  28 50 4f 52 54 3d 31 35  |ps:1521)(PORT=15|
00000090  32 31 29 29 28 43 4f 4e  4e 45 43 54 5f 44 41 54  |21))(CONNECT_DAT|
000000a0  41 3d 28 53 45 52 56 49  43 45 5f 4e 41 4d 45 3d  |A=(SERVICE_NAME=|
000000b0  57 4d 50 4c 41 32 50 50  29 28 43 49 44 3d 28 50  |WMPLA2PP)(CID=(P|
000000c0  52 4f 47 52 41 4d 3d 2f  74 6d 70 2f 67 6f 2d 62  |ROGRAM=/tmp/go-b|
000000d0  75 69 6c 64 32 36 32 36  31 38 35 39 37 2f 62 30  |uild262618597/b0|
000000e0  30 31 2f 65 78 65 2f 6d  61 69 6e 29 28 48 4f 53  |01/exe/main)(HOS|
000000f0  54 3d 72 6f 64 72 69 67  6f 2d 62 6f 6c 64 29 28  |T=rodrigo-bold)(|
00000100  55 53 45 52 3d 72 6f 64  72 69 67 6f 29 29 28 53  |USER=rodrigo))(S|
00000110  45 52 56 45 52 3d 64 65  64 69 63 61 74 65 64 29  |ERVER=dedicated)|
00000120  28 49 4e 53 54 41 4e 43  45 5f 4e 41 4d 45 3d 57  |(INSTANCE_NAME=W|
00000130  4d 50 4c 41 32 50 50 32  29 29 29                 |MPLA2PP2)))|
2021-03-08T11:19:16.7910: Redirect
2021-03-08T11:19:16.7911: Connect
2021-03-08T11:19:16.8092: 
Write packet:
00000000  01 14 00 00 01 00 00 00  01 3d 01 2c 0c 01 ff ff  |.........=.,....|
00000010  ff ff 4f 98 00 00 00 01  00 ce 00 46 00 00 00 00  |..O........F....|
00000020  01 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 ff ff 00 00  |................|
00000040  ff ff 00 00 00 00 28 44  45 53 43 52 49 50 54 49  |......(DESCRIPTI|
00000050  4f 4e 3d 28 41 44 44 52  45 53 53 3d 28 50 52 4f  |ON=(ADDRESS=(PRO|
00000060  54 4f 43 4f 4c 3d 74 63  70 29 28 48 4f 53 54 3d  |TOCOL=tcp)(HOST=|
00000070  72 61 63 61 7a 62 70 72  64 2e 6d 63 68 2e 6d 6f  |racazbprd.mch.mo|
00000080  63 2e 73 67 70 73 3a 31  35 32 31 29 28 50 4f 52  |c.sgps:1521)(POR|
00000090  54 3d 31 35 32 31 29 29  28 43 4f 4e 4e 45 43 54  |T=1521))(CONNECT|
000000a0  5f 44 41 54 41 3d 28 53  45 52 56 49 43 45 5f 4e  |_DATA=(SERVICE_N|
000000b0  41 4d 45 3d 57 4d 50 4c  41 32 50 50 29 28 43 49  |AME=WMPLA2PP)(CI|
000000c0  44 3d 28 50 52 4f 47 52  41 4d 3d 2f 74 6d 70 2f  |D=(PROGRAM=/tmp/|
000000d0  67 6f 2d 62 75 69 6c 64  32 36 32 36 31 38 35 39  |go-build26261859|
000000e0  37 2f 62 30 30 31 2f 65  78 65 2f 6d 61 69 6e 29  |7/b001/exe/main)|
000000f0  28 48 4f 53 54 3d 72 6f  64 72 69 67 6f 2d 62 6f  |(HOST=rodrigo-bo|
00000100  6c 64 29 28 55 53 45 52  3d 72 6f 64 72 69 67 6f  |ld)(USER=rodrigo|
00000110  29 29 29 29                                       |))))|
2021-03-08T11:19:16.8573: 
Read packet:
00000000  00 29 00 00 02 00 00 00  01 3b 0c 01 00 00 00 00  |.).......;......|
00000010  01 00 00 00 00 29 41 01  00 00 00 00 00 00 00 00  |.....)A.........|
00000020  00 00 20 00 00 00 ff ff  00                       |.. ......|
2021-03-08T11:19:16.8574: Handshake Complete
2021-03-08T11:19:16.8574: Advance Negotiation
2021-03-08T11:19:16.8574: 
Write packet:
00000000  00 00 00 a4 06 00 00 00  00 00 de ad be ef 00 9a  |................|
00000010  0b 20 02 00 00 04 00 00  04 00 03 00 00 00 00 00  |. ..............|
00000020  04 00 05 0b 20 02 00 00  08 00 01 00 00 10 1c 66  |.... ..........f|
00000030  ec 28 ea 00 12 00 01 de  ad be ef 00 03 00 00 00  |.(..............|
00000040  04 00 04 00 01 00 02 00  03 00 01 00 03 00 00 00  |................|
00000050  00 00 04 00 05 0b 20 02  00 00 02 00 03 e0 e1 00  |...... .........|
00000060  02 00 06 fc ff 00 02 00  03 00 00 00 00 00 04 00  |................|
00000070  05 0b 20 02 00 00 0c 00  01 00 01 08 0a 06 03 02  |.. .............|
00000080  0b 0c 0f 10 11 00 01 00  02 01 00 03 00 02 00 00  |................|
00000090  00 00 00 04 00 05 0b 20  02 00 00 06 00 01 00 01  |....... ........|
000000a0  03 04 05 06                                       |....|
2021-03-08T11:19:16.8747: 
Read packet:
00000000  00 00 00 7f 06 20 00 00  00 00 de ad be ef 00 75  |..... .........u|
00000010  00 00 00 00 00 04 00 00  04 00 03 00 00 00 00 00  |................|
00000020  04 00 05 0c 10 02 00 00  02 00 06 00 1f 00 0e 00  |................|
00000030  01 de ad be ef 00 03 00  00 00 02 00 04 00 01 00  |................|
00000040  01 00 02 00 00 00 00 00  04 00 05 0c 10 02 00 00  |................|
00000050  02 00 06 fb ff 00 02 00  02 00 00 00 00 00 04 00  |................|
00000060  05 0c 10 02 00 00 01 00  02 00 00 03 00 02 00 00  |................|
00000070  00 00 00 04 00 05 0c 10  02 00 00 01 00 02 00     |...............|
2021-03-08T11:19:16.8748: TCP Negotiation
2021-03-08T11:19:16.8748: 
Write packet:
00000000  00 00 00 1c 06 00 00 00  00 00 01 06 00 4f 72 61  |.............Ora|
00000010  63 6c 65 43 6c 69 65 6e  74 47 6f 00              |cleClientGo.|
2021-03-08T11:19:16.8886: 
Read packet:
00000000  00 00 00 ef 06 00 00 00  00 00 01 06 00 78 38 36  |.............x86|
00000010  5f 36 34 2f 4c 69 6e 75  78 20 32 2e 34 2e 78 78  |_64/Linux 2.4.xx|
00000020  00 69 03 01 0a 00 66 03  40 03 01 40 03 66 03 01  |.i....f.@[email protected]..|
00000030  66 03 48 03 01 48 03 66  03 01 66 03 52 03 01 52  |f.H..H.f..f.R..R|
00000040  03 66 03 01 66 03 61 03  01 61 03 66 03 01 66 03  |.f..f.a..a.f..f.|
00000050  1f 03 08 1f 03 66 03 01  00 64 00 00 00 60 01 24  |.....f...d...`.$|
00000060  0f 05 0b 0c 03 0c 0c 05  04 05 0d 06 09 07 08 05  |................|
00000070  05 05 05 05 0f 05 05 05  05 05 0a 05 05 05 05 05  |................|
00000080  04 05 06 07 08 08 23 47  23 47 08 11 23 08 11 41  |......#G#G..#..A|
00000090  b0 47 00 83 03 69 07 d0  03 00 00 00 00 00 00 00  |.G...i..........|
000000a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 28 06  |..............(.|
000000c0  01 01 01 2f 01 01 07 01  01 01 01 01 01 01 7f ff  |.../............|
000000d0  03 0b 03 03 01 01 ff 01  ff ff 01 0a 01 01 ff 01  |................|
000000e0  06 09 60 01 7f 04 00 07  02 01 00 01 18 00 03     |..`............|
2021-03-08T11:19:16.8887: Server Charset: 873
2021-03-08T11:19:16.8887: Server National Charset: 2000
2021-03-08T11:19:16.8888: Data Type Negotiation
2021-03-08T11:19:16.8889: 
Write packet:
00000000  00 00 0a 65 06 00 00 00  00 00 02 69 03 69 03 03  |...e.......i.i..|
00000010  29 06 01 00 00 6a 01 01  0b 01 01 01 01 01 01 00  |)....j..........|
00000020  29 90 03 07 03 00 01 00  eb 01 00 05 01 00 00 00  |)...............|
00000030  18 00 00 07 20 02 3a 00  00 05 07 02 01 00 00 00  |.... .:.........|
00000040  00 02 80 00 00 00 3c 3c  3c 80 00 00 00 00 00 00  |......<<<.......|
00000050  15 d0 07 00 01 00 01 00  01 00 00 00 02 00 02 00  |................|
00000060  0a 00 00 00 08 00 08 00  01 00 00 00 0c 00 0c 00  |................|
00000070  0a 00 00 00 17 00 17 00  01 00 00 00 18 00 18 00  |................|
00000080  01 00 00 00 19 00 19 00  01 00 00 00 1a 00 1a 00  |................|
00000090  01 00 00 00 1b 00 1b 00  01 00 00 00 1c 00 1c 00  |................|
000000a0  01 00 00 00 1d 00 1d 00  01 00 00 00 1e 00 1e 00  |................|
000000b0  01 00 00 00 1f 00 1f 00  01 00 00 00 20 00 20 00  |............ . .|
000000c0  01 00 00 00 21 00 21 00  01 00 00 00 0a 00 0a 00  |....!.!.........|
000000d0  01 00 00 00 0b 00 0b 00  01 00 00 00 28 00 28 00  |............(.(.|
000000e0  01 00 00 00 29 00 29 00  01 00 00 00 75 00 75 00  |....).).....u.u.|
000000f0  01 00 00 00 78 00 78 00  01 00 00 01 22 01 22 00  |....x.x.....".".|
00000100  01 00 00 01 23 01 23 00  01 00 00 01 24 01 24 00  |....#.#.....$.$.|
00000110  01 00 00 01 25 01 25 00  01 00 00 01 26 01 26 00  |....%.%.....&.&.|
00000120  01 00 00 01 2a 01 2a 00  01 00 00 01 2b 01 2b 00  |....*.*.....+.+.|
00000130  01 00 00 01 2c 01 2c 00  01 00 00 01 2d 01 2d 00  |....,.,.....-.-.|
00000140  01 00 00 01 2e 01 2e 00  01 00 00 01 2f 01 2f 00  |...........././.|
00000150  01 00 00 01 30 01 30 00  01 00 00 01 31 01 31 00  |....0.0.....1.1.|
00000160  01 00 00 01 32 01 32 00  01 00 00 01 33 01 33 00  |....2.2.....3.3.|
00000170  01 00 00 01 34 01 34 00  01 00 00 01 35 01 35 00  |....4.4.....5.5.|
00000180  01 00 00 01 36 01 36 00  01 00 00 01 37 01 37 00  |....6.6.....7.7.|
00000190  01 00 00 01 38 01 38 00  01 00 00 01 39 01 39 00  |....8.8.....9.9.|
000001a0  01 00 00 01 3b 01 3b 00  01 00 00 01 3c 01 3c 00  |....;.;.....<.<.|
000001b0  01 00 00 01 3d 01 3d 00  01 00 00 01 3e 01 3e 00  |....=.=.....>.>.|
000001c0  01 00 00 01 3f 01 3f 00  01 00 00 01 40 01 40 00  |....?.?.....@.@.|
000001d0  01 00 00 01 41 01 41 00  01 00 00 01 42 01 42 00  |....A.A.....B.B.|
000001e0  01 00 00 01 43 01 43 00  01 00 00 01 47 01 47 00  |....C.C.....G.G.|
000001f0  01 00 00 01 48 01 48 00  01 00 00 01 49 01 49 00  |....H.H.....I.I.|
00000200  01 00 00 01 4b 01 4b 00  01 00 00 01 4d 01 4d 00  |....K.K.....M.M.|
00000210  01 00 00 01 4e 01 4e 00  01 00 00 01 4f 01 4f 00  |....N.N.....O.O.|
00000220  01 00 00 01 50 01 50 00  01 00 00 01 51 01 51 00  |....P.P.....Q.Q.|
00000230  01 00 00 01 52 01 52 00  01 00 00 01 53 01 53 00  |....R.R.....S.S.|
00000240  01 00 00 01 54 01 54 00  01 00 00 01 55 01 55 00  |....T.T.....U.U.|
00000250  01 00 00 01 56 01 56 00  01 00 00 01 57 01 57 00  |....V.V.....W.W.|
00000260  01 00 00 01 58 01 58 00  01 00 00 01 59 01 59 00  |....X.X.....Y.Y.|
00000270  01 00 00 01 5a 01 5a 00  01 00 00 01 5c 01 5c 00  |....Z.Z.....\.\.|
00000280  01 00 00 01 5d 01 5d 00  01 00 00 01 62 01 62 00  |....].].....b.b.|
00000290  01 00 00 01 63 01 63 00  01 00 00 01 67 01 67 00  |....c.c.....g.g.|
000002a0  01 00 00 01 6b 01 6b 00  01 00 00 01 7c 01 7c 00  |....k.k.....|.|.|
000002b0  01 00 00 01 7d 01 7d 00  01 00 00 01 7e 01 7e 00  |....}.}.....~.~.|
000002c0  01 00 00 01 7f 01 7f 00  01 00 00 01 80 01 80 00  |................|
000002d0  01 00 00 01 81 01 81 00  01 00 00 01 82 01 82 00  |................|
000002e0  01 00 00 01 83 01 83 00  01 00 00 01 84 01 84 00  |................|
000002f0  01 00 00 01 85 01 85 00  01 00 00 01 86 01 86 00  |................|
00000300  01 00 00 01 87 01 87 00  01 00 00 01 89 01 89 00  |................|
00000310  01 00 00 01 8a 01 8a 00  01 00 00 01 8b 01 8b 00  |................|
00000320  01 00 00 01 8c 01 8c 00  01 00 00 01 8d 01 8d 00  |................|
00000330  01 00 00 01 8e 01 8e 00  01 00 00 01 8f 01 8f 00  |................|
00000340  01 00 00 01 90 01 90 00  01 00 00 01 91 01 91 00  |................|
00000350  01 00 00 01 94 01 94 00  01 00 00 01 95 01 95 00  |................|
00000360  01 00 00 01 96 01 96 00  01 00 00 01 97 01 97 00  |................|
00000370  01 00 00 01 9d 01 9d 00  01 00 00 01 9e 01 9e 00  |................|
00000380  01 00 00 01 9f 01 9f 00  01 00 00 01 a0 01 a0 00  |................|
00000390  01 00 00 01 a1 01 a1 00  01 00 00 01 a2 01 a2 00  |................|
000003a0  01 00 00 01 a3 01 a3 00  01 00 00 01 a4 01 a4 00  |................|
000003b0  01 00 00 01 a5 01 a5 00  01 00 00 01 a6 01 a6 00  |................|
000003c0  01 00 00 01 a7 01 a7 00  01 00 00 01 a8 01 a8 00  |................|
000003d0  01 00 00 01 a9 01 a9 00  01 00 00 01 aa 01 aa 00  |................|
000003e0  01 00 00 01 ab 01 ab 00  01 00 00 01 ad 01 ad 00  |................|
000003f0  01 00 00 01 ae 01 ae 00  01 00 00 01 af 01 af 00  |................|
00000400  01 00 00 01 b0 01 b0 00  01 00 00 01 b1 01 b1 00  |................|
00000410  01 00 00 01 c1 01 c1 00  01 00 00 01 c2 01 c2 00  |................|
00000420  01 00 00 01 c6 01 c6 00  01 00 00 01 c7 01 c7 00  |................|
00000430  01 00 00 01 c8 01 c8 00  01 00 00 01 c9 01 c9 00  |................|
00000440  01 00 00 01 ca 01 ca 00  01 00 00 01 cb 01 cb 00  |................|
00000450  01 00 00 01 cc 01 cc 00  01 00 00 01 cd 01 cd 00  |................|
00000460  01 00 00 01 ce 01 ce 00  01 00 00 01 cf 01 cf 00  |................|
00000470  01 00 00 01 d2 01 d2 00  01 00 00 01 d3 01 d3 00  |................|
00000480  01 00 00 01 d4 01 d4 00  01 00 00 01 d5 01 d5 00  |................|
00000490  01 00 00 01 d6 01 d6 00  01 00 00 01 d7 01 d7 00  |................|
000004a0  01 00 00 01 d8 01 d8 00  01 00 00 01 d9 01 d9 00  |................|
000004b0  01 00 00 01 da 01 da 00  01 00 00 01 db 01 db 00  |................|
000004c0  01 00 00 01 dc 01 dc 00  01 00 00 01 dd 01 dd 00  |................|
000004d0  01 00 00 01 de 01 de 00  01 00 00 01 df 01 df 00  |................|
000004e0  01 00 00 01 e0 01 e0 00  01 00 00 01 e1 01 e1 00  |................|
000004f0  01 00 00 01 e2 01 e2 00  01 00 00 01 e3 01 e3 00  |................|
00000500  01 00 00 01 e4 01 e4 00  01 00 00 01 e5 01 e5 00  |................|
00000510  01 00 00 01 e6 01 e6 00  01 00 00 01 ea 01 ea 00  |................|
00000520  01 00 00 01 eb 01 eb 00  01 00 00 01 ec 01 ec 00  |................|
00000530  01 00 00 01 ed 01 ed 00  01 00 00 01 ee 01 ee 00  |................|
00000540  01 00 00 01 ef 01 ef 00  01 00 00 01 f0 01 f0 00  |................|
00000550  01 00 00 01 f2 01 f2 00  01 00 00 01 f3 01 f3 00  |................|
00000560  01 00 00 01 f4 01 f4 00  01 00 00 01 f5 01 f5 00  |................|
00000570  01 00 00 01 f6 01 f6 00  01 00 00 01 fd 01 fd 00  |................|
00000580  01 00 00 01 fe 01 fe 00  01 00 00 02 01 02 01 00  |................|
00000590  01 00 00 02 02 02 02 00  01 00 00 02 04 02 04 00  |................|
000005a0  01 00 00 02 05 02 05 00  01 00 00 02 06 02 06 00  |................|
000005b0  01 00 00 02 07 02 07 00  01 00 00 02 08 02 08 00  |................|
000005c0  01 00 00 02 09 02 09 00  01 00 00 02 0a 02 0a 00  |................|
000005d0  01 00 00 02 0b 02 0b 00  01 00 00 02 0c 02 0c 00  |................|
000005e0  01 00 00 02 0d 02 0d 00  01 00 00 02 0e 02 0e 00  |................|
000005f0  01 00 00 02 0f 02 0f 00  01 00 00 02 10 02 10 00  |................|
00000600  01 00 00 02 11 02 11 00  01 00 00 02 12 02 12 00  |................|
00000610  01 00 00 02 13 02 13 00  01 00 00 02 14 02 14 00  |................|
00000620  01 00 00 02 15 02 15 00  01 00 00 02 16 02 16 00  |................|
00000630  01 00 00 02 17 02 17 00  01 00 00 02 18 02 18 00  |................|
00000640  01 00 00 02 19 02 19 00  01 00 00 02 1a 02 1a 00  |................|
00000650  01 00 00 02 1b 02 1b 00  01 00 00 02 1c 02 1c 00  |................|
00000660  01 00 00 02 1d 02 1d 00  01 00 00 02 1e 02 1e 00  |................|
00000670  01 00 00 02 1f 02 1f 00  01 00 00 02 30 02 30 00  |............0.0.|
00000680  01 00 00 02 35 02 35 00  01 00 00 02 3c 02 3c 00  |....5.5.....<.<.|
00000690  01 00 00 02 3d 02 3d 00  01 00 00 02 3e 02 3e 00  |....=.=.....>.>.|
000006a0  01 00 00 02 3f 02 3f 00  01 00 00 02 40 02 40 00  |....?.?.....@.@.|
000006b0  01 00 00 02 42 02 42 00  01 00 00 02 33 02 33 00  |....B.B.....3.3.|
000006c0  01 00 00 02 34 02 34 00  01 00 00 02 43 02 43 00  |....4.4.....C.C.|
000006d0  01 00 00 02 44 02 44 00  01 00 00 02 45 02 45 00  |....D.D.....E.E.|
000006e0  01 00 00 02 46 02 46 00  01 00 00 02 47 02 47 00  |....F.F.....G.G.|
000006f0  01 00 00 02 48 02 48 00  01 00 00 02 49 02 49 00  |....H.H.....I.I.|
00000700  01 00 00 00 03 00 02 00  0a 00 00 00 04 00 02 00  |................|
00000710  0a 00 00 00 05 00 01 00  01 00 00 00 06 00 02 00  |................|
00000720  0a 00 00 00 07 00 02 00  0a 00 00 00 09 00 01 00  |................|
00000730  01 00 00 00 0d 00 00 00  0e 00 00 00 0f 00 17 00  |................|
00000740  01 00 00 00 10 00 00 00  11 00 00 00 12 00 00 00  |................|
00000750  13 00 00 00 14 00 00 00  15 00 00 00 16 00 00 00  |................|
00000760  27 00 78 00 01 00 00 00  3a 00 00 00 44 00 02 00  |'.x.....:...D...|
00000770  0a 00 00 00 45 00 00 00  46 00 00 00 4a 00 00 00  |....E...F...J...|
00000780  4c 00 00 00 5b 00 02 00  0a 00 00 00 5e 00 01 00  |L...[.......^...|
00000790  01 00 00 00 5f 00 17 00  01 00 00 00 60 00 60 00  |...._.......`.`.|
000007a0  01 00 00 00 61 00 60 00  01 00 00 00 64 00 64 00  |....a.`.....d.d.|
000007b0  01 00 00 00 65 00 65 00  01 00 00 00 66 00 66 00  |....e.e.....f.f.|
000007c0  01 00 00 00 68 00 0b 00  01 00 00 00 69 00 00 00  |....h.......i...|
000007d0  6a 00 6a 00 01 00 00 00  6c 00 6d 00 01 00 00 00  |j.j.....l.m.....|
000007e0  6d 00 6d 00 01 00 00 00  6e 00 6f 00 01 00 00 00  |m.m.....n.o.....|
000007f0  6f 00 6f 00 01 00 00 00  70 00 70 00 01 00 00 00  |o.o.....p.p.....|
00000800  71 00 71 00 01 00 00 00  72 00 72 00 01 00 00 00  |q.q.....r.r.....|
00000810  73 00 73 00 01 00 00 00  74 00 66 00 01 00 00 00  |s.s.....t.f.....|
00000820  76 00 00 00 77 00 00 00  79 00 00 00 7a 00 00 00  |v...w...y...z...|
00000830  7b 00 00 00 88 00 00 00  92 00 92 00 01 00 00 00  |{...............|
00000840  93 00 00 00 98 00 02 00  0a 00 00 00 99 00 02 00  |................|
00000850  0a 00 00 00 9a 00 02 00  0a 00 00 00 9b 00 01 00  |................|
00000860  01 00 00 00 9c 00 0c 00  0a 00 00 00 ac 00 02 00  |................|
00000870  0a 00 00 00 b2 00 b2 00  01 00 00 00 b3 00 b3 00  |................|
00000880  01 00 00 00 b4 00 b4 00  01 00 00 00 b5 00 b5 00  |................|
00000890  01 00 00 00 b6 00 b6 00  01 00 00 00 b7 00 b7 00  |................|
000008a0  01 00 00 00 b8 00 0c 00  0a 00 00 00 b9 00 b9 00  |................|
000008b0  01 00 00 00 ba 00 ba 00  01 00 00 00 bb 00 bb 00  |................|
000008c0  01 00 00 00 bc 00 bc 00  01 00 00 00 bd 00 bd 00  |................|
000008d0  01 00 00 00 be 00 be 00  01 00 00 00 bf 00 00 00  |................|
000008e0  c0 00 00 00 c3 00 70 00  01 00 00 00 c4 00 71 00  |......p.......q.|
000008f0  01 00 00 00 c5 00 72 00  01 00 00 00 d0 00 d0 00  |......r.........|
00000900  01 00 00 00 d1 00 00 00  e7 00 e7 00 01 00 00 00  |................|
00000910  e8 00 e7 00 01 00 00 00  e9 00 e9 00 01 00 00 00  |................|
00000920  fc 00 fc 00 01 00 00 00  f1 00 6d 00 01 00 00 02  |..........m.....|
00000930  03 00 00 02 4e 02 4e 00  01 00 00 02 4f 02 4f 00  |....N.N.....O.O.|
00000940  01 00 00 02 50 02 50 00  01 00 00 02 65 02 65 00  |....P.P.....e.e.|
00000950  01 00 00 02 66 02 66 00  01 00 00 02 67 02 67 00  |....f.f.....g.g.|
00000960  01 00 00 02 68 02 68 00  01 00 00 02 63 02 63 00  |....h.h.....c.c.|
00000970  01 00 00 02 64 02 64 00  01 00 00 02 51 02 51 00  |....d.d.....Q.Q.|
00000980  01 00 00 02 52 02 52 00  01 00 00 02 53 02 53 00  |....R.R.....S.S.|
00000990  01 00 00 02 54 02 54 00  01 00 00 02 55 02 55 00  |....T.T.....U.U.|
000009a0  01 00 00 02 56 02 56 00  01 00 00 02 57 02 57 00  |....V.V.....W.W.|
000009b0  01 00 00 02 58 02 58 00  01 00 00 02 59 02 59 00  |....X.X.....Y.Y.|
000009c0  01 00 00 02 5a 02 5a 00  01 00 00 02 5b 02 5b 00  |....Z.Z.....[.[.|
000009d0  01 00 00 02 5c 02 5c 00  01 00 00 02 5d 02 5d 00  |....\.\.....].].|
000009e0  01 00 00 02 6e 02 6e 00  01 00 00 02 6f 02 6f 00  |....n.n.....o.o.|
000009f0  01 00 00 02 70 02 70 00  01 00 00 02 71 02 71 00  |....p.p.....q.q.|
00000a00  01 00 00 02 72 02 72 00  01 00 00 02 73 02 73 00  |....r.r.....s.s.|
00000a10  01 00 00 02 74 02 74 00  01 00 00 02 75 02 75 00  |....t.t.....u.u.|
00000a20  01 00 00 02 76 02 76 00  01 00 00 02 77 02 77 00  |....v.v.....w.w.|
00000a30  01 00 00 02 78 02 78 00  01 00 00 02 7d 02 7d 00  |....x.x.....}.}.|
00000a40  01 00 00 02 7e 02 7e 00  01 00 00 02 7c 02 7c 00  |....~.~.....|.|.|
00000a50  01 00 00 02 7f 02 7f 00  01 00 00 02 80 02 80 00  |................|
00000a60  01 00 00 00 00                                    |.....|
2021-03-08T11:19:16.9191: 
Read packet:
00000000  00 00 0a 48 06 00 00 00  00 00 02 80 00 00 00 3d  |...H...........=|
00000010  3c 3c 80 00 00 00 00 00  00 12 00 01 00 01 00 01  |<<..............|
00000020  00 00 00 02 00 02 00 0a  00 00 00 08 00 08 00 01  |................|
00000030  00 00 00 0c 00 0c 00 0a  00 00 00 17 00 17 00 01  |................|
00000040  00 00 00 18 00 18 00 01  00 00 00 19 00 19 00 01  |................|
00000050  00 00 00 1a 00 1a 00 01  00 00 00 1b 00 1b 00 01  |................|
00000060  00 00 00 1c 00 1c 00 01  00 00 00 1d 00 1d 00 01  |................|
00000070  00 00 00 1e 00 1e 00 01  00 00 00 1f 00 1f 00 01  |................|
00000080  00 00 00 20 00 20 00 01  00 00 00 21 00 21 00 01  |... . .....!.!..|
00000090  00 00 00 0a 00 0a 00 01  00 00 00 0b 00 0b 00 01  |................|
000000a0  00 00 00 28 00 28 00 01  00 00 00 29 00 29 00 01  |...(.(.....).)..|
000000b0  00 00 00 75 00 75 00 01  00 00 00 78 00 78 00 01  |...u.u.....x.x..|
000000c0  00 00 01 22 01 22 00 01  00 00 01 23 01 23 00 01  |...".".....#.#..|
000000d0  00 00 01 24 01 24 00 01  00 00 01 25 01 25 00 01  |...$.$.....%.%..|
000000e0  00 00 01 26 01 26 00 01  00 00 01 2a 01 2a 00 01  |...&.&.....*.*..|
000000f0  00 00 01 2b 01 2b 00 01  00 00 01 2c 01 2c 00 01  |...+.+.....,.,..|
00000100  00 00 01 2d 01 2d 00 01  00 00 01 2e 01 2e 00 01  |...-.-..........|
00000110  00 00 01 2f 01 2f 00 01  00 00 01 30 01 30 00 01  |..././.....0.0..|
00000120  00 00 01 31 01 31 00 01  00 00 01 32 01 32 00 01  |...1.1.....2.2..|
00000130  00 00 01 33 01 33 00 01  00 00 01 34 01 34 00 01  |...3.3.....4.4..|
00000140  00 00 01 35 01 35 00 01  00 00 01 36 01 36 00 01  |...5.5.....6.6..|
00000150  00 00 01 37 01 37 00 01  00 00 01 38 01 38 00 01  |...7.7.....8.8..|
00000160  00 00 01 39 01 39 00 01  00 00 01 3b 01 3b 00 01  |...9.9.....;.;..|
00000170  00 00 01 3c 01 3c 00 01  00 00 01 3d 01 3d 00 01  |...<.<.....=.=..|
00000180  00 00 01 3e 01 3e 00 01  00 00 01 3f 01 3f 00 01  |...>.>.....?.?..|
00000190  00 00 01 40 01 40 00 01  00 00 01 41 01 41 00 01  |...@[email protected]..|
000001a0  00 00 01 42 01 42 00 01  00 00 01 43 01 43 00 01  |...B.B.....C.C..|
000001b0  00 00 01 47 01 47 00 01  00 00 01 48 01 48 00 01  |...G.G.....H.H..|
000001c0  00 00 01 49 01 49 00 01  00 00 01 4b 01 4b 00 01  |...I.I.....K.K..|
000001d0  00 00 01 4d 01 4d 00 01  00 00 01 4e 01 4e 00 01  |...M.M.....N.N..|
000001e0  00 00 01 4f 01 4f 00 01  00 00 01 50 01 50 00 01  |...O.O.....P.P..|
000001f0  00 00 01 51 01 51 00 01  00 00 01 52 01 52 00 01  |...Q.Q.....R.R..|
00000200  00 00 01 53 01 53 00 01  00 00 01 54 01 54 00 01  |...S.S.....T.T..|
00000210  00 00 01 55 01 55 00 01  00 00 01 56 01 56 00 01  |...U.U.....V.V..|
00000220  00 00 01 57 01 57 00 01  00 00 01 58 01 58 00 01  |...W.W.....X.X..|
00000230  00 00 01 59 01 59 00 01  00 00 01 5a 01 5a 00 01  |...Y.Y.....Z.Z..|
00000240  00 00 01 5c 01 5c 00 01  00 00 01 5d 01 5d 00 01  |...\.\.....].]..|
00000250  00 00 01 62 01 62 00 01  00 00 01 63 01 63 00 01  |...b.b.....c.c..|
00000260  00 00 01 67 01 67 00 01  00 00 01 6b 01 6b 00 01  |...g.g.....k.k..|
00000270  00 00 01 7c 01 7c 00 01  00 00 01 7d 01 7d 00 01  |...|.|.....}.}..|
00000280  00 00 01 7e 01 7e 00 01  00 00 01 7f 01 7f 00 01  |...~.~..........|
00000290  00 00 01 80 01 80 00 01  00 00 01 81 01 81 00 01  |................|
000002a0  00 00 01 82 01 82 00 01  00 00 01 83 01 83 00 01  |................|
000002b0  00 00 01 84 01 84 00 01  00 00 01 85 01 85 00 01  |................|
000002c0  00 00 01 86 01 86 00 01  00 00 01 87 01 87 00 01  |................|
000002d0  00 00 01 89 01 89 00 01  00 00 01 8a 01 8a 00 01  |................|
000002e0  00 00 01 8b 01 8b 00 01  00 00 01 8c 01 8c 00 01  |................|
000002f0  00 00 01 8d 01 8d 00 01  00 00 01 8e 01 8e 00 01  |................|
00000300  00 00 01 8f 01 8f 00 01  00 00 01 90 01 90 00 01  |................|
00000310  00 00 01 91 01 91 00 01  00 00 01 94 01 94 00 01  |................|
00000320  00 00 01 95 01 95 00 01  00 00 01 96 01 96 00 01  |................|
00000330  00 00 01 97 01 97 00 01  00 00 01 9d 01 9d 00 01  |................|
00000340  00 00 01 9e 01 9e 00 01  00 00 01 9f 01 9f 00 01  |................|
00000350  00 00 01 a0 01 a0 00 01  00 00 01 a1 01 a1 00 01  |................|
00000360  00 00 01 a2 01 a2 00 01  00 00 01 a3 01 a3 00 01  |................|
00000370  00 00 01 a4 01 a4 00 01  00 00 01 a5 01 a5 00 01  |................|
00000380  00 00 01 a6 01 a6 00 01  00 00 01 a7 01 a7 00 01  |................|
00000390  00 00 01 a8 01 a8 00 01  00 00 01 a9 01 a9 00 01  |................|
000003a0  00 00 01 aa 01 aa 00 01  00 00 01 ab 01 ab 00 01  |................|
000003b0  00 00 01 ad 01 ad 00 01  00 00 01 ae 01 ae 00 01  |................|
000003c0  00 00 01 af 01 af 00 01  00 00 01 b0 01 b0 00 01  |................|
000003d0  00 00 01 b1 01 b1 00 01  00 00 01 c1 01 c1 00 01  |................|
000003e0  00 00 01 c2 01 c2 00 01  00 00 01 c6 01 c6 00 01  |................|
000003f0  00 00 01 c7 01 c7 00 01  00 00 01 c8 01 c8 00 01  |................|
00000400  00 00 01 c9 01 c9 00 01  00 00 01 ca 01 ca 00 01  |................|
00000410  00 00 01 cb 01 cb 00 01  00 00 01 cc 01 cc 00 01  |................|
00000420  00 00 01 cd 01 cd 00 01  00 00 01 ce 01 ce 00 01  |................|
00000430  00 00 01 cf 01 cf 00 01  00 00 01 d2 01 d2 00 01  |................|
00000440  00 00 01 d3 01 d3 00 01  00 00 01 d4 01 d4 00 01  |................|
00000450  00 00 01 d5 01 d5 00 01  00 00 01 d6 01 d6 00 01  |................|
00000460  00 00 01 d7 01 d7 00 01  00 00 01 d8 01 d8 00 01  |................|
00000470  00 00 01 d9 01 d9 00 01  00 00 01 da 01 da 00 01  |................|
00000480  00 00 01 db 01 db 00 01  00 00 01 dc 01 dc 00 01  |................|
00000490  00 00 01 dd 01 dd 00 01  00 00 01 de 01 de 00 01  |................|
000004a0  00 00 01 df 01 df 00 01  00 00 01 e0 01 e0 00 01  |................|
000004b0  00 00 01 e1 01 e1 00 01  00 00 01 e2 01 e2 00 01  |................|
000004c0  00 00 01 e3 01 e3 00 01  00 00 01 e4 01 e4 00 01  |................|
000004d0  00 00 01 e5 01 e5 00 01  00 00 01 e6 01 e6 00 01  |................|
000004e0  00 00 01 ea 01 ea 00 01  00 00 01 eb 01 eb 00 01  |................|
000004f0  00 00 01 ec 01 ec 00 01  00 00 01 ed 01 ed 00 01  |................|
00000500  00 00 01 ee 01 ee 00 01  00 00 01 ef 01 ef 00 01  |................|
00000510  00 00 01 f0 01 f0 00 01  00 00 01 f2 01 f2 00 01  |................|
00000520  00 00 01 f3 01 f3 00 01  00 00 01 f4 01 f4 00 01  |................|
00000530  00 00 01 f5 01 f5 00 01  00 00 01 f6 01 f6 00 01  |................|
00000540  00 00 01 fd 01 fd 00 01  00 00 01 fe 01 fe 00 01  |................|
00000550  00 00 02 01 02 01 00 01  00 00 02 02 02 02 00 01  |................|
00000560  00 00 02 04 02 04 00 01  00 00 02 05 02 05 00 01  |................|
00000570  00 00 02 06 02 06 00 01  00 00 02 07 02 07 00 01  |................|
00000580  00 00 02 08 02 08 00 01  00 00 02 09 02 09 00 01  |................|
00000590  00 00 02 0a 02 0a 00 01  00 00 02 0b 02 0b 00 01  |................|
000005a0  00 00 02 0c 02 0c 00 01  00 00 02 0d 02 0d 00 01  |................|
000005b0  00 00 02 0e 02 0e 00 01  00 00 02 0f 02 0f 00 01  |................|
000005c0  00 00 02 10 02 10 00 01  00 00 02 11 02 11 00 01  |................|
000005d0  00 00 02 12 02 12 00 01  00 00 02 13 02 13 00 01  |................|
000005e0  00 00 02 14 02 14 00 01  00 00 02 15 02 15 00 01  |................|
000005f0  00 00 02 16 02 16 00 01  00 00 02 17 02 17 00 01  |................|
00000600  00 00 02 18 02 18 00 01  00 00 02 19 02 19 00 01  |................|
00000610  00 00 02 1a 02 1a 00 01  00 00 02 1b 02 1b 00 01  |................|
00000620  00 00 02 1f 02 1f 00 01  00 00 02 20 00 00 02 21  |........... ...!|
00000630  00 00 02 22 00 00 02 23  00 00 02 24 00 00 02 25  |..."...#...$...%|
00000640  00 00 02 26 00 00 02 27  00 00 02 28 00 00 02 29  |...&...'...(...)|
00000650  00 00 02 2a 00 00 02 2b  00 00 02 2c 00 00 02 2d  |...*...+...,...-|
00000660  00 00 02 2e 00 00 02 2f  00 00 02 30 02 30 00 01  |......./...0.0..|
00000670  00 00 02 31 00 00 02 32  00 00 02 33 02 33 00 01  |...1...2...3.3..|
00000680  00 00 02 34 02 34 00 01  00 00 02 36 00 00 02 37  |...4.4.....6...7|
00000690  00 00 02 38 00 00 02 39  00 00 02 3a 00 00 02 3b  |...8...9...:...;|
000006a0  00 00 02 3c 02 3c 00 01  00 00 02 3d 02 3d 00 01  |...<.<.....=.=..|
000006b0  00 00 02 3e 02 3e 00 01  00 00 02 3f 02 3f 00 01  |...>.>.....?.?..|
000006c0  00 00 02 40 02 40 00 01  00 00 02 41 00 00 02 42  |...@[email protected]|
000006d0  02 42 00 01 00 00 02 43  02 43 00 01 00 00 02 44  |.B.....C.C.....D|
000006e0  02 44 00 01 00 00 02 45  02 45 00 01 00 00 02 46  |.D.....E.E.....F|
000006f0  02 46 00 01 00 00 02 47  02 47 00 01 00 00 02 48  |.F.....G.G.....H|
00000700  02 48 00 01 00 00 02 49  02 49 00 01 00 00 02 4a  |.H.....I.I.....J|
00000710  00 00 02 4b 00 00 02 4c  00 00 02 4d 00 00 02 4e  |...K...L...M...N|
00000720  02 4e 00 01 00 00 02 4f  02 4f 00 01 00 00 02 51  |.N.....O.O.....Q|
00000730  02 51 00 01 00 00 02 52  02 52 00 01 00 00 02 53  |.Q.....R.R.....S|
00000740  02 53 00 01 00 00 02 54  02 54 00 01 00 00 02 55  |.S.....T.T.....U|
00000750  02 55 00 01 00 00 02 56  02 56 00 01 00 00 02 57  |.U.....V.V.....W|
00000760  02 57 00 01 00 00 02 58  02 58 00 01 00 00 02 59  |.W.....X.X.....Y|
00000770  02 59 00 01 00 00 02 5a  02 5a 00 01 00 00 02 5b  |.Y.....Z.Z.....[|
00000780  02 5b 00 01 00 00 02 5c  02 5c 00 01 00 00 02 5d  |.[.....\.\.....]|
00000790  02 5d 00 01 00 00 02 63  02 63 00 01 00 00 02 64  |.].....c.c.....d|
000007a0  02 64 00 01 00 00 02 65  02 65 00 01 00 00 02 66  |.d.....e.e.....f|
000007b0  02 66 00 01 00 00 02 67  02 67 00 01 00 00 02 68  |.f.....g.g.....h|
000007c0  02 68 00 01 00 00 02 6e  02 6e 00 01 00 00 02 6f  |.h.....n.n.....o|
000007d0  02 6f 00 01 00 00 02 70  02 70 00 01 00 00 02 71  |.o.....p.p.....q|
000007e0  02 71 00 01 00 00 02 72  02 72 00 01 00 00 02 73  |.q.....r.r.....s|
000007f0  02 73 00 01 00 00 02 74  02 74 00 01 00 00 02 75  |.s.....t.t.....u|
00000800  02 75 00 01 00 00 02 76  02 76 00 01 00 00 02 77  |.u.....v.v.....w|
00000810  02 77 00 01 00 00 02 78  02 78 00 01 00 00 02 79  |.w.....x.x.....y|
00000820  00 00 02 7a 00 00 00 03  00 02 00 0a 00 00 00 04  |...z............|
00000830  00 02 00 0a 00 00 00 05  00 01 00 01 00 00 00 06  |................|
00000840  00 02 00 0a 00 00 00 07  00 02 00 0a 00 00 00 09  |................|
00000850  00 01 00 01 00 00 00 0d  00 00 00 0e 00 00 00 0f  |................|
00000860  00 17 00 01 00 00 00 10  00 00 00 11 00 00 00 12  |................|
00000870  00 00 00 13 00 00 00 14  00 00 00 15 00 00 00 16  |................|
00000880  00 00 00 27 00 78 00 01  00 00 00 3a 00 00 00 44  |...'.x.....:...D|
00000890  00 02 00 0a 00 00 00 45  00 00 00 46 00 00 00 4a  |.......E...F...J|
000008a0  00 00 00 4c 00 00 00 5b  00 02 00 0a 00 00 00 5e  |...L...[.......^|
000008b0  00 01 00 01 00 00 00 5f  00 17 00 01 00 00 00 60  |......._.......`|
000008c0  00 60 00 01 00 00 00 61  00 60 00 01 00 00 00 64  |.`.....a.`.....d|
000008d0  00 64 00 01 00 00 00 65  00 65 00 01 00 00 00 66  |.d.....e.e.....f|
000008e0  00 66 00 01 00 00 00 68  00 00 00 69 00 00 00 6a  |.f.....h...i...j|
000008f0  00 6a 00 01 00 00 00 6c  00 6d 00 01 00 00 00 6d  |.j.....l.m.....m|
00000900  00 6d 00 01 00 00 00 6e  00 6f 00 01 00 00 00 6f  |.m.....n.o.....o|
00000910  00 6f 00 01 00 00 00 70  00 70 00 01 00 00 00 71  |.o.....p.p.....q|
00000920  00 71 00 01 00 00 00 72  00 72 00 01 00 00 00 73  |.q.....r.r.....s|
00000930  00 73 00 01 00 00 00 74  00 66 00 01 00 00 00 76  |.s.....t.f.....v|
00000940  00 00 00 79 00 00 00 7a  00 00 00 7b 00 00 00 88  |...y...z...{....|
00000950  00 00 00 92 00 92 00 01  00 00 00 93 00 00 00 98  |................|
00000960  00 02 00 0a 00 00 00 99  00 02 00 0a 00 00 00 9a  |................|
00000970  00 02 00 0a 00 00 00 9b  00 01 00 01 00 00 00 9c  |................|
00000980  00 0c 00 0a 00 00 00 ac  00 02 00 0a 00 00 00 b2  |................|
00000990  00 b2 00 01 00 00 00 b3  00 b3 00 01 00 00 00 b4  |................|
000009a0  00 b4 00 01 00 00 00 b5  00 b5 00 01 00 00 00 b6  |................|
000009b0  00 b6 00 01 00 00 00 b7  00 b7 00 01 00 00 00 b8  |................|
000009c0  00 0c 00 0a 00 00 00 b9  00 00 00 ba 00 00 00 bb  |................|
000009d0  00 00 00 bc 00 00 00 bd  00 00 00 be 00 00 00 bf  |................|
000009e0  00 00 00 c0 00 00 00 c3  00 70 00 01 00 00 00 c4  |.........p......|
000009f0  00 71 00 01 00 00 00 c5  00 72 00 01 00 00 00 d0  |.q.......r......|
00000a00  00 d0 00 01 00 00 00 d1  00 00 00 e7 00 e7 00 01  |................|
00000a10  00 00 00 e8 00 e7 00 01  00 00 00 e9 00 e9 00 01  |................|
00000a20  00 00 00 f1 00 6d 00 01  00 00 00 f5 00 00 00 f6  |.....m..........|
00000a30  00 00 00 fa 00 00 00 fb  00 00 00 fc 00 fc 00 01  |................|
00000a40  00 00 02 03 00 00 00 00                           |........|
2021-03-08T11:19:16.9194: TTC Version: 7
2021-03-08T11:19:16.9195: doAuth
2021-03-08T11:19:16.9195: 
Write packet:
00000000  00 00 00 a1 06 00 00 00  00 00 03 76 00 01 01 06  |...........v....|
00000010  01 01 01 01 05 01 01 06  61 75 74 6f 71 61 01 0d  |........autoqa..|
00000020  0d 41 55 54 48 5f 54 45  52 4d 49 4e 41 4c 01 0c  |.AUTH_TERMINAL..|
00000030  0c 72 6f 64 72 69 67 6f  2d 62 6f 6c 64 00 01 0f  |.rodrigo-bold...|
00000040  0f 41 55 54 48 5f 50 52  4f 47 52 41 4d 5f 4e 4d  |.AUTH_PROGRAM_NM|
00000050  01 04 04 6d 61 69 6e 00  01 0c 0c 41 55 54 48 5f  |...main....AUTH_|
00000060  4d 41 43 48 49 4e 45 01  0c 0c 72 6f 64 72 69 67  |MACHINE...rodrig|
00000070  6f 2d 62 6f 6c 64 00 01  08 08 41 55 54 48 5f 50  |o-bold....AUTH_P|
00000080  49 44 01 05 05 39 37 32  31 34 00 01 08 08 41 55  |ID...97214....AU|
00000090  54 48 5f 53 49 44 01 07  07 72 6f 64 72 69 67 6f  |TH_SID...rodrigo|
000000a0  00                                                |.|
2021-03-08T11:19:16.9499: 
Read packet:
00000000  00 00 01 50 06 00 00 00  00 00 08 01 06 01 0c 0c  |...P............|
00000010  41 55 54 48 5f 53 45 53  53 4b 45 59 01 40 40 36  |AUTH_SESSKEY.@@6|
00000020  43 33 41 36 46 32 43 31  45 33 35 32 42 31 43 46  |C3A6F2C1E352B1CF|
00000030  43 42 44 35 38 41 43 37  46 44 46 33 37 46 34 42  |CBD58AC7FDF37F4B|
00000040  32 35 43 37 45 32 34 41  43 42 46 31 41 33 37 39  |25C7E24ACBF1A379|
00000050  44 30 44 41 35 36 44 31  46 30 32 44 30 36 42 00  |D0DA56D1F02D06B.|
00000060  01 0d 0d 41 55 54 48 5f  56 46 52 5f 44 41 54 41  |...AUTH_VFR_DATA|
00000070  00 02 09 39 01 14 14 41  55 54 48 5f 50 42 4b 44  |...9...AUTH_PBKD|
00000080  46 32 5f 43 53 4b 5f 53  41 4c 54 01 20 20 44 37  |F2_CSK_SALT.  D7|
00000090  42 33 41 37 42 46 38 37  38 39 30 43 35 37 46 35  |B3A7BF87890C57F5|
000000a0  45 46 41 34 32 37 33 42  33 35 30 39 39 38 00 01  |EFA4273B350998..|
000000b0  16 16 41 55 54 48 5f 50  42 4b 44 46 32 5f 56 47  |..AUTH_PBKDF2_VG|
000000c0  45 4e 5f 43 4f 55 4e 54  01 04 04 34 30 39 36 00  |EN_COUNT...4096.|
000000d0  01 16 16 41 55 54 48 5f  50 42 4b 44 46 32 5f 53  |...AUTH_PBKDF2_S|
000000e0  44 45 52 5f 43 4f 55 4e  54 01 01 01 33 00 01 1a  |DER_COUNT...3...|
000000f0  1a 41 55 54 48 5f 47 4c  4f 42 41 4c 4c 59 5f 55  |.AUTH_GLOBALLY_U|
00000100  4e 49 51 55 45 5f 44 42  49 44 00 01 20 20 31 34  |NIQUE_DBID..  14|
00000110  31 45 32 33 35 45 39 32  37 46 44 38 39 39 37 36  |1E235E927FD89976|
00000120  31 42 42 44 35 42 32 39  32 36 43 42 30 39 00 04  |1BBD5B2926CB09..|
00000130  01 01 01 02 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
2021-03-08T11:19:16.9503: 
Write packet:
00000000  00 00 03 ae 06 00 00 00  00 00 03 73 00 01 01 06  |...........s....|
00000010  02 01 01 01 01 0f 01 01  06 61 75 74 6f 71 61 01  |.........autoqa.|
00000020  0c 0c 41 55 54 48 5f 53  45 53 53 4b 45 59 01 40  |..AUTH_SESSKEY.@|
00000030  40 41 37 44 42 33 35 42  32 42 42 38 34 35 36 41  |@A7DB35B2BB8456A|
00000040  43 42 39 32 33 36 35 35  41 32 34 45 36 32 42 36  |CB923655A24E62B6|
00000050  44 44 37 37 42 33 39 39  41 37 35 42 44 31 44 30  |DD77B399A75BD1D0|
00000060  38 36 36 36 42 36 32 36  46 34 30 41 33 35 45 31  |8666B626F40A35E1|
00000070  42 01 01 01 0d 0d 41 55  54 48 5f 50 41 53 53 57  |B.....AUTH_PASSW|
00000080  4f 52 44 01 40 40 43 34  35 39 37 45 41 41 38 34  |ORD.@@C4597EAA84|
00000090  32 41 34 42 35 38 31 41  33 34 38 41 33 43 44 46  |2A4B581A348A3CDF|
000000a0  38 36 37 34 30 36 36 44  39 41 43 45 37 45 36 33  |8674066D9ACE7E63|
000000b0  44 31 43 38 37 41 42 30  44 44 37 37 36 43 38 38  |D1C87AB0DD776C88|
000000c0  39 45 46 43 38 45 00 01  16 16 41 55 54 48 5f 50  |9EFC8E....AUTH_P|
000000d0  42 4b 44 46 32 5f 53 50  45 45 44 59 5f 4b 45 59  |BKDF2_SPEEDY_KEY|
000000e0  01 40 40 33 30 41 38 41  32 43 31 37 32 34 45 33  |.@@30A8A2C1724E3|
000000f0  32 32 45 33 30 37 43 32  34 35 34 44 31 42 42 46  |22E307C2454D1BBF|
00000100  44 32 33 33 43 45 30 35  37 30 39 34 43 30 43 31  |D233CE057094C0C1|
00000110  39 44 35 36 35 34 45 31  30 46 36 41 41 32 37 30  |9D5654E10F6AA270|
00000120  44 33 46 00 01 0d 0d 41  55 54 48 5f 54 45 52 4d  |D3F....AUTH_TERM|
00000130  49 4e 41 4c 01 0c 0c 72  6f 64 72 69 67 6f 2d 62  |INAL...rodrigo-b|
00000140  6f 6c 64 00 01 0f 0f 41  55 54 48 5f 50 52 4f 47  |old....AUTH_PROG|
00000150  52 41 4d 5f 4e 4d 01 04  04 6d 61 69 6e 00 01 0c  |RAM_NM...main...|
00000160  0c 41 55 54 48 5f 4d 41  43 48 49 4e 45 01 0c 0c  |.AUTH_MACHINE...|
00000170  72 6f 64 72 69 67 6f 2d  62 6f 6c 64 00 01 08 08  |rodrigo-bold....|
00000180  41 55 54 48 5f 50 49 44  01 05 05 39 37 32 31 34  |AUTH_PID...97214|
00000190  00 01 08 08 41 55 54 48  5f 53 49 44 01 07 07 72  |....AUTH_SID...r|
000001a0  6f 64 72 69 67 6f 00 01  13 13 41 55 54 48 5f 43  |odrigo....AUTH_C|
000001b0  4f 4e 4e 45 43 54 5f 53  54 52 49 4e 47 01 ce ce  |ONNECT_STRING...|
000001c0  28 44 45 53 43 52 49 50  54 49 4f 4e 3d 28 41 44  |(DESCRIPTION=(AD|
000001d0  44 52 45 53 53 3d 28 50  52 4f 54 4f 43 4f 4c 3d  |DRESS=(PROTOCOL=|
000001e0  74 63 70 29 28 48 4f 53  54 3d 72 61 63 61 7a 62  |tcp)(HOST=racazb|
000001f0  70 72 64 2e 6d 63 68 2e  6d 6f 63 2e 73 67 70 73  |prd.mch.moc.sgps|
00000200  3a 31 35 32 31 29 28 50  4f 52 54 3d 31 35 32 31  |:1521)(PORT=1521|
00000210  29 29 28 43 4f 4e 4e 45  43 54 5f 44 41 54 41 3d  |))(CONNECT_DATA=|
00000220  28 53 45 52 56 49 43 45  5f 4e 41 4d 45 3d 57 4d  |(SERVICE_NAME=WM|
00000230  50 4c 41 32 50 50 29 28  43 49 44 3d 28 50 52 4f  |PLA2PP)(CID=(PRO|
00000240  47 52 41 4d 3d 2f 74 6d  70 2f 67 6f 2d 62 75 69  |GRAM=/tmp/go-bui|
00000250  6c 64 32 36 32 36 31 38  35 39 37 2f 62 30 30 31  |ld262618597/b001|
00000260  2f 65 78 65 2f 6d 61 69  6e 29 28 48 4f 53 54 3d  |/exe/main)(HOST=|
00000270  72 6f 64 72 69 67 6f 2d  62 6f 6c 64 29 28 55 53  |rodrigo-bold)(US|
00000280  45 52 3d 72 6f 64 72 69  67 6f 29 29 29 29 00 01  |ER=rodrigo))))..|
00000290  16 16 53 45 53 53 49 4f  4e 5f 43 4c 49 45 4e 54  |..SESSION_CLIENT|
000002a0  5f 43 48 41 52 53 45 54  01 03 03 38 37 33 00 01  |_CHARSET...873..|
000002b0  17 17 53 45 53 53 49 4f  4e 5f 43 4c 49 45 4e 54  |..SESSION_CLIENT|
000002c0  5f 4c 49 42 5f 54 59 50  45 01 01 01 30 00 01 1a  |_LIB_TYPE...0...|
000002d0  1a 53 45 53 53 49 4f 4e  5f 43 4c 49 45 4e 54 5f  |.SESSION_CLIENT_|
000002e0  44 52 49 56 45 52 5f 4e  41 4d 45 01 0e 0e 4f 72  |DRIVER_NAME...Or|
000002f0  61 63 6c 65 43 6c 69 65  6e 74 47 6f 00 01 16 16  |acleClientGo....|
00000300  53 45 53 53 49 4f 4e 5f  43 4c 49 45 4e 54 5f 56  |SESSION_CLIENT_V|
00000310  45 52 53 49 4f 4e 01 07  07 32 2e 30 2e 30 2e 30  |ERSION...2.0.0.0|
00000320  00 01 16 16 53 45 53 53  49 4f 4e 5f 43 4c 49 45  |....SESSION_CLIE|
00000330  4e 54 5f 4c 4f 42 41 54  54 52 01 01 01 31 00 01  |NT_LOBATTR...1..|
00000340  12 12 41 55 54 48 5f 41  4c 54 45 52 5f 53 45 53  |..AUTH_ALTER_SES|
00000350  53 49 4f 4e 01 55 55 41  4c 54 45 52 20 53 45 53  |SION.UUALTER SES|
00000360  53 49 4f 4e 20 53 45 54  20 4e 4c 53 5f 4c 41 4e  |SION SET NLS_LAN|
00000370  47 55 41 47 45 3d 27 41  4d 45 52 49 43 41 4e 27  |GUAGE='AMERICAN'|
00000380  20 4e 4c 53 5f 54 45 52  52 49 54 4f 52 59 3d 27  | NLS_TERRITORY='|
00000390  41 4d 45 52 49 43 41 27  20 20 54 49 4d 45 5f 5a  |AMERICA'  TIME_Z|
000003a0  4f 4e 45 3d 27 30 30 3a  30 30 27 00 01 01        |ONE='00:00'...|
2021-03-08T11:19:17.9758: 
Read packet:
00000000  00 00 00 0b 0c 20 00 00  01 00 01                 |..... .....|
2021-03-08T11:19:17.9759: 
Read packet:
00000000  00 00 00 0b 0c 20 00 00  01 00 02                 |..... .....|
2021-03-08T11:19:17.9759: 
Write packet:
00000000  00 00 00 0b 0c 00 00 00  01 00 02                 |...........|
2021-03-08T11:19:17.9956: 
Read packet:
00000000  00 00 00 62 06 00 00 00  00 00 04 01 01 00 00 02  |...b............|
00000010  03 f9 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 02 03 f9 00 33 4f  |..............3O|
00000030  52 41 2d 30 31 30 31 37  3a 20 69 6e 76 61 6c 69  |RA-01017: invali|
00000040  64 20 75 73 65 72 6e 61  6d 65 2f 70 61 73 73 77  |d username/passw|
00000050  6f 72 64 3b 20 6c 6f 67  6f 6e 20 64 65 6e 69 65  |ord; logon denie|
00000060  64 0a                                             |d.|

Rounding error

Hi,
I'm doing another test with the package:

SELECT count(*) FROM help

This show a rounding error:

go run .
Topics:  918.9999999999999

I was expecting 919.
Thanks for your work

Parser Error?

SQL stmt that doesn't return record.

This does not work

var sqlStmt = `
SELECT 
   ID_RECORD,
   DESCRIPTION,
   DEBUG_
from DEVELOPERS.MVTEST
`

This work

var sqlStmt = `SELECT ID_RECORD, DESCRIPTION, DEBUG_ from DEVELOPERS.MVTEST`

There is a parser problem ?

By

Support New Charset (need testing)

I add support for the following charset (decoding only):
1- 0x33D. JA16VMS
2-0x33E. JA16EUC
3- 0x33F. JA16EUCYEN
4- 0x340. JA16SJIS
5- 0x352. ZHS16CGB231280
6- 0x353. ZHS16MACCGB231280
7- 0x354. ZHS16GBK

Change log prints only to Debug mode

Hi @sijms ,

After the resolution of the issue #23 , there is 3 lines that is always printing logs.

Lines that is generating the prints:

// all data returned from the server
fmt.Println("data returned: ", data) 

// redirect address
fmt.Println("redirect address: ", pck.redirectAddr)

// reconnect data
fmt.Println("reconnect data: ", pck.reconnectData)

Is it possible to change the code to print these 3 lines only when running in Debug mode?

Decimal numbers are not correctly retrieved

I have found that decimal numbers are retrieved as integer.

The following query

Select 2*1/3 from DUAL

returns 0 when expecting something like 0,6666666666666666666666666666666666666667

Here is the test code:

func main() {
	conn, err := sql.Open("oracle", "oracle://system:[email protected]/xe")
	OKorDie(err)
	defer conn.Close()

	stmt, err := conn.Prepare("Select 2*1/3 from DUAL")
	OKorDie(err)
	defer stmt.Close()

	rows, err := stmt.Query()
	OKorDie(err)
	defer rows.Close()

	for rows.Next() {
		var N sql.NullFloat64
		err = rows.Scan(&N)
		OKorDie(err)
		fmt.Println("N: ", N)
	}
}

ORA-06502: PL/SQL: numeric or value error

package main

import (
"database/sql"
"fmt"

_ "github.com/sijms/go-ora"

)

func main() {
fmt.Println("main")

db, err := sql.Open("oracle", "oracle://scott:[email protected]:1521/orcl")
defer db.Close()
if err != nil {
	fmt.Println("[sql.Open ERR]:", err)
	return
}

err = db.Ping()
if err != nil {
	fmt.Println("[db.Ping ERR]:", err)
	return
}

}

[db.Ping ERR]: ORA-06502: PL/SQL: numeric or value error
ORA-06512: at line 16

Connection String

Thanks for this work.

I'm using another package today to connect to Oracle. Here is how I connect:

oraProd := "user/password@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dbs001.cores.com)(PORT=53701))(CONNECT_DATA=(SID=DBSPROD)))"

db, err := sql.Open("oci8", oraProd)

Can you give me the syntax I would use to construct the connection string for your package?

thanks,

Runtime panic due to slice out of bounds

Hi,

I think you already mentioned this one and probably already working on it.
Can you please take a look? Thanks!

panic: runtime error: slice bounds out of range [:292] with capacity 16
goroutine 1 [running]:
github.com/sijms/go-ora/network.newRedirectPacketFromData
.../go/src/github.com/sijms/go-ora/network/redirect_packet.go:41
github.com/sijms/go-ora/network.(*Session).readPacket
.../go/src/github.com/sijms/go-ora/network/session.go:272
github.com/sijms/go-ora/network.(*Session).Connect
.../go/src/github.com/sijms/go-ora/network/session.go:76
github.com/sijms/go-ora.(*Connection).Open
.../go/src/github.com/sijms/go-ora/connection.go:234

Can't read more than 1 row having a LONG field

Sorry to keep you busy.

I have used 60bc60e for this test.

So I have a table having following structure:

Name         Null?    Type           
------------ -------- -------------- 
BUF_ID       NOT NULL NVARCHAR2(20)  
BUF_NAME     NOT NULL NVARCHAR2(100) 
BUF_SETTINGS NOT NULL LONG           
BUF_USE_UID           NVARCHAR2(20)  

This table has 28 rows.

The application uses this field to store some XML structure.

I'm querying the table with ./examples/query/main.go program. I get just one row.

When looking in trace file, the 1st frame has more than one record, and there is one more frame with the rest of the table.

I think the issue is here:

go-ora/data_set.go

Lines 113 to 131 in 60bc60e

if dataSet.parent.hasMoreRows && dataSet.index != 0 && dataSet.index%dataSet.parent.noOfRowsToFetch == 0 {
dataSet.Rows = make([]Row, 0, dataSet.parent.noOfRowsToFetch)
err := dataSet.parent.fetch(dataSet)
if err != nil {
return err
}
}
if dataSet.parent.hasMoreRows && (dataSet.parent.hasBLOB || dataSet.parent.hasLONG) && dataSet.index == 0 {
if err := dataSet.parent.fetch(dataSet); err != nil {
return err
}
}
if dataSet.index%dataSet.parent.noOfRowsToFetch < len(dataSet.Rows) {
for x := 0; x < len(dataSet.Rows[dataSet.index%dataSet.parent.noOfRowsToFetch]); x++ {
dest[x] = dataSet.Rows[dataSet.index%dataSet.parent.noOfRowsToFetch][x]
}
dataSet.index++
return nil
}

The call to Next fetches the 1st record at line 121, but for next calls, nothing is fetched, and Next returns io.EOF

Panicking at Prepare

Hi,

I'm very happy to see your package. Get ride of oci DLL will simplify compilation. Thank you!

I'm testing you package against a basic dockerized oracle server (https://hub.docker.com/r/oracleinanutshell/oracle-xe-11g). I'm able to run the query below using sql developer.

The program works fine under linux, but panics at Prepare under windows.
Unfortunately, enterprise system is not linux :-<

package main

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

   _ "github.com/sijms/go-ora"
)

func OKorDie(err error) {
   if err != nil {
   	fmt.Println(err)
   	os.Exit(-1)
   }
}

func main() {
   conn, err := sql.Open("oracle", "oracle://system:[email protected]/xe")
   OKorDie(err)
   defer conn.Close()

   stmt, err := conn.Prepare("SELECT distinct(TOPIC)  FROM help")
   OKorDie(err)
   defer stmt.Close()

   rows, err := stmt.Query()
   OKorDie(err)
   defer rows.Close()

   for rows.Next() {
   	var topic string
   	err = rows.Scan(&topic)
   	OKorDie(err)
   	fmt.Println("Topics: ", topic)
   }
}
go version go1.15.3 windows/amd64
github.com/sijms/go-ora/network.newRefusePacketFromData(0xc000092110, 0xc, 0x10, 0x0)
	C:/Users/me/go/src/github.com/sijms/go-ora/network/refuse_packet.go:43 +0x285
github.com/sijms/go-ora/network.(*Session).readPacket(0xc0000a4000, 0x0, 0x0, 0x0, 0x0)
	C:/Users/me/go/src/github.com/sijms/go-ora/network/session.go:270 +0x2a5
github.com/sijms/go-ora/network.(*Session).Connect(0xc0000a4000, 0x0, 0x0)
	C:/Users/me/go/src/github.com/sijms/go-ora/network/session.go:76 +0x411
github.com/sijms/go-ora.(*Connection).Open(0xc0000a0000, 0x0, 0x0)
	C:/Users/me/go/src/github.com/sijms/go-ora/connection.go:234 +0x14a
github.com/sijms/go-ora.(*oracleDriver).Open(0xd94588, 0xb48cf6, 0x27, 0x0, 0x0, 0x0, 0x0)
	C:/Users/me/go/src/github.com/sijms/go-ora/connection.go:79 +0xf4
database/sql.dsnConnector.Connect(0xb48cf6, 0x27, 0xb6ab40, 0xd94588, 0xb6c380, 0xc000012028, 0x0, 0x0, 0x0, 0x0)
	c:/go/src/database/sql/sql.go:707 +0x84
database/sql.(*DB).conn(0xc000048ea0, 0xb6c380, 0xc000012028, 0xc00007db01, 0x0, 0x0, 0x0)
	c:/go/src/database/sql/sql.go:1294 +0xdc4
database/sql.(*DB).prepare(0xc000048ea0, 0xb6c380, 0xc000012028, 0xb4761d, 0x21, 0x1000000000001, 0x0, 0x0, 0x0)
	c:/go/src/database/sql/sql.go:1482 +0x9b
database/sql.(*DB).PrepareContext(0xc000048ea0, 0xb6c380, 0xc000012028, 0xb4761d, 0x21, 0x0, 0x0, 0x0)
	c:/go/src/database/sql/sql.go:1455 +0xd4
database/sql.(*DB).Prepare(0xc000048ea0, 0xb4761d, 0x21, 0x0, 0x0, 0x0)
	c:/go/src/database/sql/sql.go:1472 +0xb5
main.main()
	C:/Users/me/go/src/github.com/simulot/go-ora/main.go:26 +0x17f
Process exiting with code: 0

rows.Next() skips first records

I'm using the exemple/query tool for dumping all records of a view. But some records are missing!

For testing, I have used the HR example database:

SELECT * from HR.EMP_DETAILS_VIEW

EMPLOYEE_ID JOB_ID     MANAGER_ID DEPARTMENT_ID LOCATION_ID CO FIRST_NAME           LAST_NAME                     SALARY COMMISSION_PCT DEPARTMENT_NAME                JOB_TITLE                           CITY                           STATE_PROVINCE            COUNTRY_NAME                             REGION_NAME              
----------- ---------- ---------- ------------- ----------- -- -------------------- ------------------------- ---------- -------------- ------------------------------ ----------------------------------- ------------------------------ ------------------------- ---------------------------------------- -------------------------
        100 AD_PRES                          90        1700 US Steven               King                           24000                Executive                      President                           Seattle                        Washington                United States of America                 Americas                 
        101 AD_VP             100            90        1700 US Neena                Kochhar                        17000                Executive                      Administration Vice President       Seattle                        Washington                United States of America                 Americas                 
        102 AD_VP             100            90        1700 US Lex                  De Haan                        17000                Executive                      Administration Vice President       Seattle                        Washington                United States of America                 Americas                 


...
        206 AC_ACCOUNT        205           110        1700 US William              Gietz                           8300                Accounting                     Public Accountant                   Seattle                        Washington                United States of America                 Americas                 

returns 106 record.

you can use go-ora\exemple\query to reproduce the problem:

go run . -server oracle://system:[email protected]/xe  "SELECT * from HR.EMP_DETAILS_VIEW" 

You'll get 81 records... Firsts are missing:

Note the 1st EMPLOYEE_ID

-- Record # 1 ----------------------------------------
EMPLOYEE_ID              : 125
JOB_ID                   : ST_CLERK
MANAGER_ID               : 120
DEPARTMENT_ID            : 50
LOCATION_ID              : 1500
COUNTRY_ID               : US

...


-- Record # 81 ----------------------------------------
EMPLOYEE_ID              : 206
JOB_ID                   : AC_ACCOUNT
MANAGER_ID               : 205
DEPARTMENT_ID            : 110
LOCATION_ID              : 1700
...

I have checked the trace file, and missing records are present in the log:

00000780  00 04 01 01 01 06 01 19  00 00 00 01 01 01 12 03  |................|
00000790  00 00 00 00 00 00 00 00  00 00 00 00 00 00 01 01  |................|
000007a0  00 00 00 00                                       |....|
2020-11-26T16:28:46.7919: Summary: RetCode:0, Error Message:""
2020-11-26T16:28:46.7919: Row 0
2020-11-26T16:28:46.7919:   EMPLOYEE_ID         : 100
2020-11-26T16:28:46.7919:   JOB_ID              : AD_PRES
2020-11-26T16:28:46.7919:   MANAGER_ID          : <nil>
2020-11-26T16:28:46.7919:   DEPARTMENT_ID       : 90
2020-11-26T16:28:46.7919:   LOCATION_ID         : 1700
2020-11-26T16:28:46.7919:   COUNTRY_ID          : US
2020-11-26T16:28:46.7919:   FIRST_NAME          : Steven
2020-11-26T16:28:46.7919:   LAST_NAME           : King
2020-11-26T16:28:46.7919:   SALARY              : 24000

ORA-00911: invalid character

hi! thanks for this great project.

I encounter an error when I use chinese word as a column alias. eg.:

select sysdate ไธญๆ–‡ from dual

it gets ORA-00911: invalid character.

I cloned the repo and made some changes to converters/string_conversion.go. and it runs fine. wish that helps.

if you are willing to accept a pr I will be happy to start one.
if not, since that commit imports an external module, I'll be still happy to work out another solution, like exposing an interface:

type IStringConverter interface{
    Encode(string) []byte
    Decode([]byte) string
}

to let the client code to register their own encoder/decoder.

Driver doesn't support sys_refcursor parameter

I have an oracle Procedure like, which returns a sys_refcursor:

PROCEDURE getTTVT
    (
        o_data OUT sys_refcursor   
    )
    IS
     v_Query varchar2(4000);
    BEGIN
    v_Query :='
       select unit_id, unit_name
       from admin_hcm.unit where unit_id in (41, 42, 43, 44, 45, 56, 57, 59, 60)
    ';
     OPEN o_data FOR v_Query;
END getTTVT;

My go function is:

// Unit of list
type Unit struct {
	unit_id int64
	unit_name string
}
func ListAllUnits {
        stmt, err := db.oracleDB.Prepare("begin dashboard.getTTVT(); end;")
	if err != nil {
		fmt.Println("Error create statment")
		fmt.Println(err)
		return nil, err
	}
	defer stmt.Close()
	units := []models.Unit{}
	result, err := stmt.Exec(sql.Out{Dest: &units})
	fmt.Println(result)
}
func main() {
   ListAllUnits()
}

When I run command:

go run main.go

I only get nil
@sijms Can you explain how to call Oracle Store Procedure?

ใ€columnTypeใ€‘Cannot get the right of column.

Excuse me.

As the title says, when the type is VARCHAR2, I only get NCHAR.

I have read your source code, in parameter.go, I also not found VARCHAR2.
So how can I finish this?

The following is part of my code

colums, err := rows.Columns()
types, err := rows.ColumnTypes()
for k := range colums {
	log.Println(colums[k],types[k].DatabaseTypeName())
}

// output
INFO[0000] COLUMN_1 NCHAR                               
INFO[0000] COLUMN_2 CHAR                                
INFO[0000] COLUMN_3 NCHAR                               
INFO[0000] COLUMN_4 NUMBER                              
INFO[0000] COLUMN_5 NUMBER

This is the real Type.
image

Error when reading many records having large field

I have found this problem using a copy of production database.

When querying a very simple table using a select * from MY_TABLE , i have a random problem that could be either:

  • premature stop reading, with last read record corrupted
  • hang
  • error saying the paquet is not data

The problem isn't related to the number of records. I'm able to query several million of records. It's more related to the use of
NVARCHAR2 with a large enough data.

For debugging purpose, I made a self contained sample to illustrate the problem.
This program create a table similar to production:

Name      Null?    Type            
--------- -------- --------------- 
RECNUMBER NOT NULL NUMBER          
LABEL     NOT NULL NVARCHAR2(20)   
TEXT               NVARCHAR2(2000) 

Then it fills the with records having TEXT field as bigger as possible.
My database is using AL32UTF8 char set. I think this is what we call UNICODE 32 bits, where each chars is encoded using 32 bits. So 2000 chars makes 4000 bytes.

Like the production application, it generates a long string to be stored into the table, using several records, and uses the maximum of the NVARCHAR2(2000) room.

package main

import (
	"database/sql/driver"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

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

func exitOnError(err error) {
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

const (
	RecordSize = 2000
	TotalSize  = 140000
)

func main() {
	server := os.Getenv("DB_DEV1") + "?TRACE FILE=Trace.log"

	db, err := go_ora.NewConnection(server)
	err = db.Open()
	exitOnError(err)
	defer db.Close()

	err = CreateTable(db, RecordSize)
	exitOnError(err)

	rec := GenerateData(TotalSize, RecordSize)
	err = CreateRecords(db, rec)
	exitOnError(err)

	read, err := GetRecords(db)
	exitOnError(err)

	fmt.Println("Want ", len(rec), "records")
	fmt.Println("Got  ", len(read), "records")

	i := 0
	for i < len(rec) && i < len(read) {
		if rec[i] != read[i] {
			fmt.Println("Records", i, "are different")
			fmt.Println("Want\n", rec[i])
			fmt.Println("Got\n", read[i])
		}
		i++
	}
}

func CreateTable(DB *go_ora.Connection, recordSize int) error {

	stmt := go_ora.NewStmt("drop table TEST_TABLE", DB)
	_, err := stmt.Exec(nil)
	defer stmt.Close()

	stmt = go_ora.NewStmt(`CREATE TABLE TEST_TABLE 
	(
	  RECNUMBER NUMBER NOT NULL 
	, LABEL NVARCHAR2(20) NOT NULL 
	, TEXT NVARCHAR2(`+strconv.Itoa(recordSize)+`) 
	)`, DB)
	_, err = stmt.Exec(nil)

	return err
}

func CreateRecords(DB *go_ora.Connection, r []string) error {

	for i, s := range r {

		stmt := go_ora.NewStmt("insert into TEST_TABLE(RECNUMBER,LABEL,TEXT) values (:1,:2,:3)", DB)
		recLabel := fmt.Sprintf("Rec %d", i)

		stmt.AddParam("1", i, 0, go_ora.Input /* or go_ora.Output*/)
		stmt.AddParam("2", recLabel, len(recLabel), go_ora.Input /* or go_ora.Output*/)
		stmt.AddParam("3", s, len(s), go_ora.Input /* or go_ora.Output*/)
		_, err := stmt.Exec(nil)
		if err != nil {
			return err
		}
		stmt.Close()
	}
	fmt.Println("Record ", len(r), "inserted")
	return nil
}

func GetRecords(DB *go_ora.Connection) ([]string, error) {
	ret := []string{}
	stmt := go_ora.NewStmt("select RECNUMBER,LABEL,TEXT from TEST_TABLE order by RECNUMBER", DB)

	rows, err := stmt.Query(nil)
	if err != nil {
		return nil, err
	}

	values := []driver.Value{0, 0, 0}
	for {
		err = rows.Next(values)
		if err != nil {
			break
		}
		ret = append(ret, values[2].(string))
	}

	if err != io.EOF {
		return nil, err
	}
	return ret, nil
}

func GenerateData(length int, sliceOf int) []string {
	s := strings.Builder{}
	i := 0

	for s.Len() < length {
		s.WriteString(fmt.Sprintf("%010d,", i))
		i++
	}

	buf := []byte(s.String())
	ret := []string{}
	for len(buf) > 0 {
		l := len(buf)
		if l > sliceOf {
			l = sliceOf
		}
		ret = append(ret, string(buf[:l]))
		buf = buf[l:]
	}

	return ret
}

The call to GenerateData(140000, 2000) creates a dataset of 140 000 chars, sliced into 2000 chars records.

For those values, the programs fails most of the time, never at the same record.

Record  71 inserted
Want  71 records
Got   65 records
Records 64 are different
Want
 011636,0000011637,0000011638,0000011639,0000011640,0000011641,0000011642,0000011643,0000011644,0000011645,0000011646,0000011647,0000011648,0000011649,0000011650,0000011651,0000011652,0000011653,0000011654,0000011655,0000011656,0000011657,0000011658,0000011659,0000011660,0000011661,0000011662,0000011663,0000011664,0000011665,0000011666,0000011667,0000011668,0000011669,0000011670,0000011671,0000011672,0000011673,0000011674,0000011675,0000011676,0000011677,0000011678,0000011679,0000011680,0000011681,0000011682,0000011683,0000011684,0000011685,0000011686,0000011687,0000011688,0000011689,0000011690,0000011691,0000011692,0000011693,0000011694,0000011695,0000011696,0000011697,0000011698,0000011699,0000011700,0000011701,0000011702,0000011703,0000011704,0000011705,0000011706,0000011707,0000011708,0000011709,0000011710,0000011711,0000011712,0000011713,0000011714,0000011715,0000011716,0000011717,0000011718,0000011719,0000011720,0000011721,0000011722,0000011723,0000011724,0000011725,0000011726,0000011727,0000011728,0000011729,0000011730,0000011731,0000011732,0000011733,0000011734,0000011735,0000011736,0000011737,0000011738,0000011739,0000011740,0000011741,0000011742,0000011743,0000011744,0000011745,0000011746,0000011747,0000011748,0000011749,0000011750,0000011751,0000011752,0000011753,0000011754,0000011755,0000011756,0000011757,0000011758,0000011759,0000011760,0000011761,0000011762,0000011763,0000011764,0000011765,0000011766,0000011767,0000011768,0000011769,0000011770,0000011771,0000011772,0000011773,0000011774,0000011775,0000011776,0000011777,0000011778,0000011779,0000011780,0000011781,0000011782,0000011783,0000011784,0000011785,0000011786,0000011787,0000011788,0000011789,0000011790,0000011791,0000011792,0000011793,0000011794,0000011795,0000011796,0000011797,0000011798,0000011799,0000011800,0000011801,0000011802,0000011803,0000011804,0000011805,0000011806,0000011807,0000011808,0000011809,0000011810,0000011811,0000011812,0000011813,0000011814,0000011815,0000011816,0000011817,00
Got
 011636,0000011637,0000011638,0000011639,0000011640,0000011641,0000011642,0000011643,0000011644,0000011645,0000011646,0000011647,0000011648,0000011649,0000011650,0000011651,0000011652,0000011653,0000011654,0000011655,0000011656,0000011657,000001165  ใ €โฐ€ใ€€ใ€€ใ€€ใ€€1๏ผ€ใ„€ใ˜€ใ”€ใค€โฐ€ใ€€ใ€€ใ€€ใ€€ใ€€ใ„€ใ„€ใ˜€ใ˜€ใ€€โฐ€ใ€€ใ€€ใ€€ใ€€ใ€€ใ„€661,0000011662,000001166 โฐ€ใ€€ใ€€ใ€€ใ€€ใ€€ใ„€ใ„€ใ˜€ใ˜€ใ€โฐ€ใ€€ใ€€ใ€€ใ€€ใ€€ใ„€ใ„€ใ˜€ใ˜€ใ”€โฐ€ใ€€ใ€€0011666,0000011667,00000

The table is correct.

Date are always UTC

I have found that datetime are returned in UTC regardless local time, session settings, database settings.

Assuming my sever is UTC, my session EST, and the local time EST

At 2020-11-16 19:58:10 local time , using go-ora to select CURRENT_DATE from dual returns 2020-11-16 19:58:10 +0000 UTC

The current code sets the the location to UTC in all circumstances:

return time.Date(year, time.Month(data[2]), int(data[3]),
int(data[4]-1)+tzHour, int(data[5]-1)+tzMin, int(data[6]-1), nanoSec, time.UTC), nil

I propose to investigate on this, and propose a PR.
++

Security scan using gosec

Did a security scan with https://github.com/securego/gosec
And got the following results.

Results:

Golang errors in file: [/home/testuser/code/golang/go-ora/auth_object.go]:

[line 13 : column 2] - could not import github.com/sijms/go-ora/network (invalid package name: "")

Golang errors in file: [/home/testuser/code/golang/go-ora/command.go]:

[line 10 : column 2] - could not import github.com/sijms/go-ora/converters (invalid package name: "")

[/home/testuser/code/golang/go-ora/auth_object.go:363] - G401 (CWE-326): Use of weak cryptographic primitive (Confidence: HIGH, Severity: MEDIUM)
362: func CalculateKeysHash(verifierType int, key1 []byte, key2 []byte) ([]byte, error) {

363: hash := md5.New()
364: switch verifierType {

[/home/testuser/code/golang/go-ora/auth_object.go:260] - G401 (CWE-326): Use of weak cryptographic primitive (Confidence: HIGH, Severity: MEDIUM)
259: ret := make([]byte, 8)

260: enc, err := des.NewCipher(key)
261: if err != nil {

[/home/testuser/code/golang/go-ora/auth_object.go:91] - G401 (CWE-326): Use of weak cryptographic primitive (Confidence: HIGH, Severity: MEDIUM)
90: result = append([]byte(password), result...)

91: hash := sha1.New()
92: hash.Write(result)

[/home/testuser/code/golang/go-ora/auth_object.go:10] - G505 (CWE-327): Blocklisted import crypto/sha1: weak cryptographic primitive (Confidence: HIGH, Severity: MEDIUM)
9: "crypto/rand"

10: "crypto/sha1"
11: "errors"

[/home/testuser/code/golang/go-ora/auth_object.go:8] - G501 (CWE-327): Blocklisted import crypto/md5: weak cryptographic primitive (Confidence: HIGH, Severity: MEDIUM)
7: "crypto/des"

8: "crypto/md5"
9: "crypto/rand"

[/home/testuser/code/golang/go-ora/auth_object.go:7] - G502 (CWE-327): Blocklisted import crypto/des: weak cryptographic primitive (Confidence: HIGH, Severity: MEDIUM)
6: "crypto/cipher"

7: "crypto/des"
8: "crypto/md5"

[/home/testuser/code/golang/go-ora/auth_object.go:381] - G104 (CWE-703): Errors unhandled. (Confidence: HIGH, Severity: LOW)
380: hash.Reset()

381: hash.Write(buffer[16:])
382: ret = append(ret, hash.Sum(nil)...)

[/home/testuser/code/golang/go-ora/auth_object.go:378] - G104 (CWE-703): Errors unhandled. (Confidence: HIGH, Severity: LOW)
377: }

378: hash.Write(buffer[:16])
379: ret := hash.Sum(nil)

[/home/testuser/code/golang/go-ora/auth_object.go:371] - G104 (CWE-703): Errors unhandled. (Confidence: HIGH, Severity: LOW)
370:

371: hash.Write(buffer)
372: return hash.Sum(nil), nil

[/home/testuser/code/golang/go-ora/auth_object.go:92] - G104 (CWE-703): Errors unhandled. (Confidence: HIGH, Severity: LOW)
91: hash := sha1.New()

92: hash.Write(result)
93: key = hash.Sum(nil) // 20 byte key

Summary:
Files: 11
Lines: 3407
Nosec: 0
Issues: 10

Certain fields are not retreived (returned as null)

Hi,
I was able to see a lot of progress after fixing the previous issue. Most of the data is properly retrieved, but in certain cases NULL is retrieved instead. No error is reported by the Scan function.

I am still trying to narrow down the cases and find possible patterns.
One case that appears consistent is when on a VARCHAR2(128 byte) field there is a dash (-) or underscore (_)

The second case is more mysterious, it is a NUMBER column, with all the rows containing a number 1.
The firs half (aprox) is properly retrieved, but the other is presented as null. I couldn't find yet any difference between the two groups.

Anyway, in general the module compiles and behaves quite fast. Not needing to carry around a bunch of libraries is another big plus. Hope this one can be solved as well :)

Thanks!

Select with dblink will report error

I use dblink syntax to query oracle db๏ผŒthe command.go will report error. because dataSet.currentRow == nil. dataSet.currentRow[x] will report panic: runtime error: index out of range [0] with length 0. Break point can find the column name but can not get currentRow.

The error stack is as follows๏ผš
panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
github.com/sijms/go-ora.(*Stmt).read(0xc000294380, 0xc0002de000, 0x0, 0x0)
F:/workSpace/goWorkSpace/pkg/mod/github.com/sijms/[email protected]/command.go:567 +0x39b9
github.com/sijms/go-ora.(*Stmt).Query(0xc000294380, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
F:/workSpace/goWorkSpace/pkg/mod/github.com/sijms/[email protected]/command.go:1060 +0x541

Wrong connection string but sql.Open returns nil error nonetheless

I wanted to try this module out, and realized I hadn't passed any address parameters to the connection string. It still hadn't caused any errors. So when I tried the code below it still resulted with success(!).

package oracledb_test

import (
	"database/sql"
	"testing"

	_ "github.com/sijms/go-ora"
)

func TestGora(t *testing.T) {
	conn, err := sql.Open("oracle", "oracle://aa:AA@aa")
	if err != nil {
		t.Fatal(err.Error())
	}
	defer conn.Close()

	t.Log("success")
}

Error from leading comments in SQL statement

During the course of migrating from godror to go-ora we encountered a minor regression. Our application reads SQL queries from a text file. The queries are rather complex and often contain documentation related comments. If the first line of the query is a comment, we are getting an error, if a comment is anywhere else in the file it parses and executes. We did not experience this behavior with godror. I tried looking at the code for godror to see if they handle query parsing differently but haven't had much luck.

Ex: This query works

SELECT *
FROM USERS
/* comment here */
WHERE id = 1

This does not work

/* This query begins with a comment */
SELECT *
FROM USERS
WHERE id = 1

crash on stmt.Close()

i deployed my program on both 12c and 11g, the program crash or has error when connecting to oracle db.
check on log oracle:

  1. case crash:
    log on Oracle
2020-12-10T23:44:12.599539+07:00
Session (3594,30260): Bad TTC Packet Detected: Inbound connection from client
Session (3594,30260): Bad TTC Packet Detected: DB Logon User: admin, Remote Machine: dboracle , Program: plugin-oracle, OS User: root
Session (3594,30260): Bad TTC Packet Detected: Could not find Client IP Address 
AOM_10/12/2020 23:46:57_7495252196
2020-12-10T23:47:12.500474+07:00
Errors in file /u01/app/oracle/diag/rdbms/cdb/cdb1/trace/cdb1_s000_67521.trc  (incident=462390) (PDBNAME=CDB$ROOT):
ORA-03137: malformed TTC packet from client rejected: [12209] [0] [] [] [] [] [] []
  1. Case not crash
    log oracle
    Dumping diagnostic data in directory=[cdmp_20201210141311], requested by (instance=1, osid=90994 (S005)), summary=[incident=1180777].
    Thu Dec 10 14:16:11 2020
    Dumping diagnostic data in directory=[cdmp_20201210141611], requested by (instance=1, osid=90998 (S007)), summary=[incident=1180793].
    Thu Dec 10 14:17:25 2020
    Errors in file /u01/app/oracle/diag/rdbms/hddt/HDDT2/trace/HDDT2_s013_105611.trc (incident=1692458):
    ORA-03137: TTC protocol internal error : [12209] [0] [] [] [] [] [] []
    Incident details in: /u01/app/oracle/diag/rdbms/hddt/HDDT2/incident/incdir_1692458/HDDT2_s013_105611_i1692458.trc
    Thu Dec 10 14:17:33 2020
    Errors in file /u01/app/oracle/diag/rdbms/hddt/HDDT2/trace/HDDT2_s001_105583.trc (incident=1692354):
    ORA-03137: TTC protocol internal error : [12209] [0] [] [] [] [] [] []
    Incident details in: /u01/app/oracle/diag/rdbms/hddt/HDDT2/incident/incdir_1692354/HDDT2_s001_105583_i1692354.trc
    Both case, Oracle DB create too much trace files, and they increased rapidly (several millions trace file within 1 day)

I made a trace on my program:

error start from: rows, err := stmt.Query(nil)
panic at: session.inBuffer = append(session.inBuffer, dataPck.buffer...)

if dataPck, ok := pck.(*DataPacket); ok {
session.inBuffer = append(session.inBuffer, dataPck.buffer...)
} else {
return nil, errors.New("the packet received is not data packet")
}

ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] time="2020-12-11T15:36:42+07:00" level=error msg="========dataPck========= &{{10 241 6 0} 0 ["(Much data i remove)" source="session.go:233"  source="client.go:1022"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] time="2020-12-11T15:36:42+07:00" level=error msg="========dataPck========= &{{10 2548 6 0} 0 ["(Much data i remove)"" source="session.go:233"  source="client.go:1022"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] time="2020-12-11T15:36:42+07:00" level=error msg="========dataPck========= &{{10 266 6 0} 0 ["(Much data i remove)"" source="session.go:233"  source="client.go:1022"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] time="2020-12-11T15:36:43+07:00" level=error msg="========dataPck========= <nil>" source="session.go:233"  source="client.go:1022"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] time="2020-12-11T15:36:43+07:00" level=error msg="Oracle plugin: cannot close stmt EOF" source="oracle_exporter.go:199"  source="client.go:1022"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] panic: runtime error: invalid memory address or nil pointer dereference  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] [signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x9779aa]  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin]                          source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] goroutine 53 [running]:  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] oracle-plugin/vendor/github.com/sijms/go-ora/network.(*Session).read(0xc0003dc000, 0x1, 0xc00035c480, 0x100000020, 0x20, 0xc0004689a0, 0x2)  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin]  D://Go projects/src/oracle-plugin/vendor/github.com/sijms/go-ora/network/session.go:234 +0x1ea  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] oracle-plugin/vendor/github.com/sijms/go-ora/network.(*Session).GetByte(0xc0003dc000, 0x0, 0xc0004689a0, 0xc0004517a0)  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin]  D://Go projects/src/oracle-plugin/vendor/github.com/sijms/go-ora/network/session.go:641 +0x34  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] oracle-plugin/vendor/github.com/sijms/go-ora.(*Stmt).read(0xc000430380, 0xc000258280, 0x0, 0x0)  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin]  D://Go projects/src/oracle-plugin/vendor/github.com/sijms/go-ora/command.go:409 +0xb5  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] oracle-plugin/vendor/github.com/sijms/go-ora.(*Stmt).Query(0xc000430380, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin]  D://Go projects/src/oracle-plugin/vendor/github.com/sijms/go-ora/command.go:1060 +0x3e9  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] main.sendCommandGetParams(0xc0003be8c0, 0x0, 0x0, 0x0)  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin]  D://Go projects/src/oracle-plugin/oracle_exporter.go:202 +0xed  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] main.(*oracleCollector).getConfig(0xc000146a40, 0xc00013fa10, 0xc, 0x5f1, 0xc00013fa20, 0x6, 0xc00013a960, 0x13, 0xc00013fa26, 0x3, ...)  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin]  D://Go projects/src/oracle-plugin/oracle_exporter.go:157 +0x776  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin] created by main.(*oracleCollector).Update  source="client.go:1024"
ERRO[11 Dec 20 15:36 ICT] [oracle-plugin]  D://Go projects/src/oracle-plugin/oracle_exporter.go:121 +0x24b  source="client.go:1024"

After i add "dataPck != nil"

	if dataPck, ok := pck.(*DataPacket); ok &&  dataPck != nil {
		session.inBuffer = append(session.inBuffer, dataPck.buffer...)
	} else {
		return nil, errors.New("the packet received is not data packet")
	}

the program still panic at err := rows.Close()
ERRO[11 Dec 20 16:13 ICT] [oracle-plugin] time="2020-12-11T16:13:23+07:00" level=error msg="rows is <nil>" source="oracle_exporter.go:207" source="client.go:1022"

after handler rows==nil, there are only 2 errors


ERRO[11 Dec 20 16:20 ICT] [oracle-plugin] time="2020-12-11T16:20:53+07:00" level=error msg="Oracle plugin: cannot execute query the packet received is not data packet" source="oracle_exporter.go:204"  source="client.go:1022"
ERRO[11 Dec 20 16:20 ICT] [oracle-plugin] time="2020-12-11T16:20:53+07:00" level=error msg="Oracle plugin: cannot close stmt EOF" source="oracle_exporter.go:199"  source="client.go:1022"

slice bounds out of range during rows.Next()

Please see stack trace below in *Session.GetInt64 during rows.Next(). Not yet sure if I can reproduce the issue. But perhaps looking at this error might give some ideas to the circumstance in which this happened.

panic: runtime error: slice bounds out of range [-117:]

goroutine 59 [running]:
github.com/sijms/go-ora/network.(*Session).GetInt64(0xc0004ee480, 0x7d, 0x9c0101, 0x4526af, 0xc002d9bdb0, 0x7f7d0cd03d78)
/Users/xxx/go/src/git.dev.e2open.com/chnshp/watermill-users/vendor/github.com/sijms/go-ora/network/session.go:717 +0x229
github.com/sijms/go-ora/network.(*Session).GetInt(0xc0004ee480, 0x1, 0xc002dc0101, 0x1, 0xb97, 0x0)
/Users/xxx/go/src/git.dev.e2open.com/chnshp/watermill-users/vendor/github.com/sijms/go-ora/network/session.go:730 +0x4b
github.com/sijms/go-ora/network.(*Session).GetClr(0xc0004ee480, 0xb, 0xc002d4cca0, 0xba2, 0xc002d9bdb0, 0xb)
/Users/xxx/go/src/git.dev.e2open.com/chnshp/watermill-users/vendor/github.com/sijms/go-ora/network/session.go:779 +0x210
github.com/sijms/go-ora.(*defaultStmt).read(0xc002a0b040, 0xc00cef6380, 0x0, 0x10102)
/Users/xxx/go/src/git.dev.e2open.com/chnshp/watermill-users/vendor/github.com/sijms/go-ora/command.go:584 +0x433
github.com/sijms/go-ora.(*defaultStmt).fetch(0xc002a0b040, 0xc00cef6380, 0x19, 0xc000e52780)
/Users/xxx/go/src/git.dev.e2open.com/chnshp/watermill-users/vendor/github.com/sijms/go-ora/command.go:472 +0x1ce
github.com/sijms/go-ora.(*DataSet).Next(0xc00cef6380, 0xc001f0bc00, 0xa9, 0xa9, 0xc000151ce8, 0x40d8db)
/Users/xxx/go/src/git.dev.e2open.com/chnshp/watermill-users/vendor/github.com/sijms/go-ora/data_set.go:122 +0x2fa
database/sql.(*Rows).nextLocked(0xc003952200, 0x0)
/usr/local/go/src/database/sql/sql.go:2865 +0xbf
database/sql.(*Rows).Next.func1()
/usr/local/go/src/database/sql/sql.go:2843 +0x3c

Can not get rows with "direct use of the package"

Here is the code i used to get result:
```
result := make(go_ora.Row,25)
rows.Next(result)
log.Infoln(result)

But the result is not corect

`time="2020-09-17T10:24:53+07:00" level=info msg="[lock_name_space <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>]" source="oracle_exporter_test.go:89"`

after debug, i problem is in this code"
if dataSet.index%dataSet.parent.noOfRowsToFetch < len(dataSet.Rows) {
	for x := 0; x < len(dataSet.Rows[dataSet.index%dataSet.parent.noOfRowsToFetch]); x++ {
		dest[x] = driver.Value(dataSet.Rows[dataSet.index%dataSet.parent.noOfRowsToFetch][x])
	}
	dataSet.index++
	return nil
}

i changed to 

if (dataSet.parent.hasMoreRows) {
	if (dataSet.index > 0) {
		dataSet.Rows = make([]Row, 0, dataSet.parent.noOfRowsToFetch)
		err := dataSet.parent.fetch(dataSet)
		if err != nil {
			return err
		}
	}
	for x:=0; x <len(dataSet.Rows); x++ {
		//log.Infoln(dataSet.index, dataSet.Rows[x])
		dataSet.index++
	}

	return nil
} else {
	return io.EOF
}
It has result, but it will panic:

goroutine 37 [running]:

testing.tRunner.func1(0xc000186200)
C:/Go/src/testing/testing.go:874 +0x3aa
panic(0xc00b20, 0xc000062ea0)
C:/Go/src/runtime/panic.go:679 +0x1c0
ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora/network.(*Session).GetInt64(0xc0001681e0, 0x33, 0x101, 0x2bd, 0x0, 0x0)
D:/Work/Programming Project/Go projects/src/ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora/network/session.go:581 +0x376
ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora/network.(*Session).GetInt(0xc0001681e0, 0x2, 0x101, 0x0, 0x0, 0x0)
D:/Work/Programming Project/Go projects/src/ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora/network/session.go:595 +0x52
ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora.(*DataSet).read(0xc0000a6660, 0xc0001681e0, 0x0, 0x0)
D:/Work/Programming Project/Go projects/src/ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora/data_set.go:28 +0x67
ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora.(*Stmt).read(0xc0000ae790, 0xc0000a6660, 0x0, 0x10102)
D:/Work/Programming Project/Go projects/src/ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora/command.go:495 +0xd4a
ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora.(*Stmt).fetch(0xc0000ae790, 0xc0000a6660, 0x19, 0xc0001f4000)
D:/Work/Programming Project/Go projects/src/ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora/command.go:257 +0x211
ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora.(*DataSet).Next(0xc0000a6660, 0xc00009d040, 0x19, 0x19, 0x0, 0x0)
D:/Work/Programming Project/Go projects/src/ncms-agent/core/plugins/ncms-plugin-oracle/vendor/github.com/sijms/go-ora/data_set.go:83 +0xc7
ncms-agent/core/plugins/ncms-plugin-oracle.TestMetrics(0xc000186200)
D:/Work/Programming Project/Go projects/src/ncms-agent/core/plugins/ncms-plugin-oracle/oracle_exporter_test.go:99 +0x242

If I change stmt.noOfRowsToFetch = 25 to bigger like 30, no more panic but the result is lack off
when i reduce it to 10. it worked.
Can you resolve this problem?

No more than 50 rows are returned with last release.

Using github.com/sijms/go-ora v0.0.0-20210313181832-b64036f0a8e4, the result is limited to only 50 rows, even if there is more.

with the release github.com/sijms/go-ora v0.0.0-20210301201657-604392efe05f it works fine (returns the correct rows of 72).

ORA-03120: two-task conversion routine: integer overflow

When I run same query second time, I got the ORA-03120 error.
ORA-03120: two-task conversion routine: integer overflow

I can get the query result first time in loop, but it went wrong in second time.

`
db, err := sql.Open("oracle", connectStr)
if err != nil {
log.Println("ERR! Oracle open error")
log.Fatal(err)
}
defer db.Close()

... ...

stmt, err := db.Prepare(โ€œ... some query with parameter ... โ€)
// check error

for v := range patternList {
result, err := stmt.Query(v)
// check error
}
`

Can not get rows with "direct use of the package"

I can not comment in closed isue.
continue issue #2
I replaced 25 by 2 (column name and value) but it still error. Here is the code (it worked with modified library)

url := fmt.Sprintf("oracle://%s:%s@%s:%d/%s", "admin", "admin", "localhost", 1521, "test")
	conn, err := go_ora.NewConnection(url)
	if err != nil {
		log.Errorln("Oracle plugin can not connect to instance: ", err)
	}
	err = conn.Open()
	stmt := go_ora.NewStmt("select name,value from v$parameter", conn)
	defer func() {
		err := stmt.Close()
		if err != nil {
			if err != nil {
				log.Errorln("Oracle plugin: can not close stmt", err)
			}

		}
	}()
	rows, err := stmt.Query(nil)
	if (err != nil) {
		log.Errorln("Oracle plugin: can not execute query", err)
	}
	defer func() {
		err := rows.Close()
		if err != nil {
			log.Errorln("Oracle plugin: can not close rows", err)
		}
	}()
	results := make(go_ora.Row, 2)
	for {
		if err == io.EOF {
			break
		}
		err = rows.Next(results)
		for _, result := range results {
			str := fmt.Sprintf("%v", result)
			resultArray := strings.Split(str, " ")
			log.Infoln(resultArray)
		}
	}

Error

panic: runtime error: index out of range [2] with length 2 [recovered]
	panic: runtime error: index out of range [2] with length 2

goroutine 20 [running]:
testing.tRunner.func1(0xc000168200)
	C:/Go/src/testing/testing.go:874 +0x3aa
panic(0xade300, 0xc00017c6e0)
	C:/Go/src/runtime/panic.go:679 +0x1c0
test_project/vendor/github.com/sijms/go-ora.(*DataSet).Next(0xc00016a180, 0xc00016f5e0, 0x2, 0x2, 0xc2ac20, 0xc00016a180)
	D:/src/test_project/vendor/github.com/sijms/go-ora/data_set.go:88 +0x1c1
test_project.TestMetrics1(0xc000168200)
	D:/src/test_project/oracle_exporter_test.go:135 +0x4cb
testing.tRunner(0xc000168200, 0xb6ae00)
	C:/Go/src/testing/testing.go:909 +0xd0
created by testing.(*T).Run
	C:/Go/src/testing/testing.go:960 +0x357

Process finished with exit code 1

if i change "results := make(go_ora.Row, 10)", the result have some duplicate rows.

Problem with Oracle 11g

Hi Sijms.
With oracle 12c, the lib worked perfectly. but when I used with oracle 11g. The error ORA-01882: timezone region not found. How to disable this parameter oracle.jdbc.timezoneAsRegion=false ?

Can't connect to my employer's servers

Hi,
After having tested go-ora with an ad hoc server, I would like to connect entreprises servers.

At the moment the server and the port are correct, whatever I try as user / pwd / SID, I get a panic:

github.com/sijms/go-ora/network.newRefusePacketFromData(0xc000012230, 0xc, 0x10, 0xc)
        C:/Users/me/go/src/github.com/sijms/go-ora/network/refuse_packet.go:43 +0x165
github.com/sijms/go-ora/network.(*Session).readPacket(0xc0000021e0, 0x0, 0x0, 0x0, 0x105)
        C:/Users/me/go/src/github.com/sijms/go-ora/network/session.go:270 +0x10c
github.com/sijms/go-ora/network.(*Session).Connect(0xc0000021e0, 0xc0000021e0, 0x10600)
        C:/Users/me/go/src/github.com/sijms/go-ora/network/session.go:76 +0x2a9
github.com/sijms/go-ora.(*Connection).Open(0xc00004a280, 0x31, 0xc00004a280)
        C:/Users/me/go/src/github.com/sijms/go-ora/connection.go:232 +0x1a5
github.com/sijms/go-ora.(*oracleDriver).Open(0x17215a8, 0x14c5d95, 0x31, 0x0, 0x0, 0x30000, 0x1320000)
        C:/Users/me/go/src/github.com/sijms/go-ora/connection.go:79 +0x85
database/sql.dsnConnector.Connect(...)
        c:/go/src/database/sql/sql.go:707
database/sql.(*DB).conn(0xc00004edd0, 0x14f1580, 0xc000012028, 0xc000040001, 0x14f1540, 0xc00004edd0, 0xc000040040)
        c:/go/src/database/sql/sql.go:1294 +0x214
database/sql.(*DB).prepare(0xc00004edd0, 0x14f1580, 0xc000012028, 0x14c6f53, 0x7f, 0x14efb01, 0x17215a8, 0x16d2750, 0xb82aeb9cf40c44fc)
        c:/go/src/database/sql/sql.go:1482 +0x5f
database/sql.(*DB).PrepareContext(0xc00004edd0, 0x14f1580, 0xc000012028, 0x14c6f53, 0x7f, 0x0, 0x0, 0x13ff794)
        c:/go/src/database/sql/sql.go:1455 +0xa5
database/sql.(*DB).Prepare(...)
        c:/go/src/database/sql/sql.go:1472
main.main()
        C:/Users/me/go/src/github.com/simulot/go-ora/main.go:23 +0xff

I can't do the test using linux, because of company's VPN not allowed on linux.
How can I help you with this problem without disclosing company's credentials?
++

Missing license

Thank you for developing this!

Two questions:

  1. This project seems to be missing a license - which license is this made available under?

  2. Was this client developed using the source of an existing Oracle library? (I'm mostly curious since its rare to find a client that doesn't rely on Oracle's SDK)

Panic when client receive redirect packet

Hi,

Aftter create a connection and open, I'm getting error at prepare statement.

My Connection function:

func Connect() (*sql.DB, error) {

	db, err := sql.Open("oracle", "oracle://USER:PASS@URL/SERVICE")

	if err != nil {
		return nil, err
	}

	return db, nil

}

My Work function:

func (t *TestData) GetDBValue() (err error) {

	//Connecting to Oracle DB here...
	db, err := oracle.Connect()
	if err != nil {
		return helpers.Error("It was not possible to connect to the database ", err)
	}
	defer db.Close()

	stmt, err := db.Prepare("SELECT * FROM DUAL WHERE 1 = :1")
	if err != nil {
		return helpers.Error("Error preparing query ", err)
	}
	defer stmt.Close()
	rows, err := stmt.Query(1)
	if err != nil {
		return helpers.Error("Error running query ", err)
	}
	defer rows.Close()
}

Error:

Error At this line: stmt, err := db.Prepare("SELECT * FROM DUAL WHERE 1 = :1")


runtime error: slice bounds out of range [:310] with capacity 16
runtime.gopanic
        /usr/local/go/src/runtime/panic.go:969
runtime.goPanicSliceAcap
        /usr/local/go/src/runtime/panic.go:106
github.com/sijms/go-ora/network.newRedirectPacketFromData
        /home/rodrigo/myProject/vendor/github.com/sijms/go-ora/network/redirect_packet.go:41
github.com/sijms/go-ora/network.(*Session).readPacket
        /home/rodrigo/myProject/vendor/github.com/sijms/go-ora/network/session.go:272
github.com/sijms/go-ora/network.(*Session).Connect
        /home/rodrigo/myProject/vendor/github.com/sijms/go-ora/network/session.go:76
github.com/sijms/go-ora.(*Connection).Open
        /home/rodrigo/myProject/vendor/github.com/sijms/go-ora/connection.go:232
github.com/sijms/go-ora.(*oracleDriver).Open
        /home/rodrigo/myProject/vendor/github.com/sijms/go-ora/connection.go:79
database/sql.dsnConnector.Connect
        /usr/local/go/src/database/sql/sql.go:707
database/sql.(*DB).conn
        /usr/local/go/src/database/sql/sql.go:1294
database/sql.(*DB).prepare
        /usr/local/go/src/database/sql/sql.go:1482
database/sql.(*DB).PrepareContext
        /usr/local/go/src/database/sql/sql.go:1455
database/sql.(*DB).Prepare
        /usr/local/go/src/database/sql/sql.go:1472
myProject/steps.(*TestData).CreateDOs
        /home/rodrigo/myProject/steps/steps.go:178
reflect.Value.call
        /usr/local/go/src/reflect/value.go:475
reflect.Value.Call
        /usr/local/go/src/reflect/value.go:336
github.com/cucumber/godog/internal/models.(*StepDefinition).Run
        /home/rodrigo/myProject/vendor/github.com/cucumber/godog/internal/models/stepdef.go:159
github.com/cucumber/godog.(*suite).runStep
        /home/rodrigo/myProject/vendor/github.com/cucumber/godog/suite.go:138
github.com/cucumber/godog.(*suite).runSteps
        /home/rodrigo/myProject/vendor/github.com/cucumber/godog/suite.go:225
github.com/cucumber/godog.(*suite).runPickle
        /home/rodrigo/myProject/vendor/github.com/cucumber/godog/suite.go:284
github.com/cucumber/godog.(*runner).concurrent.func1
        /home/rodrigo/myProject/vendor/github.com/cucumber/godog/run.go:111
runtime.goexit
        /usr/local/go/src/runtime/asm_amd64.s:1374

Thanks!

Materialized View

Hi, I try to SELECT from the materialized view but I don't get any records.
It's a missing feature?

Thanks
Franco

ORA-03137 Bad TTC Packet

Hi,
Oracle logs an error in the alert_SID.log upon 1st request or ping, subsequent requests or pings do not trigger another alert.

2021-01-25T17:27:35.456074+01:00
Session (65,29529): Bad TTC Packet Detected: Inbound connection from client
Session (65,29529): Bad TTC Packet Detected: DB Logon User: XXXXXX, Remote Machine: XXXXXXXX, Program: testme, OS User: XXXXXX
Session (65,29529): Bad TTC Packet Detected: Client IP Address: XX.XX.XX.XX

Here is the code :

package main

import (
    "database/sql"
    "log"

    _ "github.com/sijms/go-ora" // Oracle driver
)

func main() {
    connString := "oracle://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

    conn, err := sql.Open("oracle", connString)
    if err != nil {
        log.Print(err)
        return
    }
    defer conn.Close()
    log.Print(conn.Ping())
}

The database version is Oracle 12.2, and I have no idea of what's hapening. The queries get executed correctly, there is no error other than this message.
The DBA here are ranting about it, hence this issue.

Fails to compile with GOOS=linux, GOARCH=386

I'm not sure if you're intentionally avoiding 32-bit systems, but if I compile an application using go-ora with the flags GOOS=linux GOARCH=386, I get the following error:

# github.com/sijms/go-ora/advanced_nego
../../../../go/pkg/mod/github.com/sijms/[email protected]/advanced_nego/advanced_nego.go:40:9: constant 3735928559 overflows int
../../../../go/pkg/mod/github.com/sijms/[email protected]/advanced_nego/advanced_nego.go:120:17: constant 3735928559 overflows int
../../../../go/pkg/mod/github.com/sijms/[email protected]/advanced_nego/supervisor_service.go:60:10: constant 3735928559 overflows int
../../../../go/pkg/mod/github.com/sijms/[email protected]/advanced_nego/supervisor_service.go:91:17: constant 3735928559 overflows int

These errors can probably be fixed by having the functions explicitly return int64, I think.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.