Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose OCINumber (dpiNumber) #100

Open
felipenoris opened this issue Feb 26, 2019 · 20 comments
Open

Expose OCINumber (dpiNumber) #100

felipenoris opened this issue Feb 26, 2019 · 20 comments

Comments

@felipenoris
Copy link

felipenoris commented Feb 26, 2019

See commit in branch https://github.com/felipenoris/odpi/tree/fn/numeric.

The following changes allow odpi users to bind and read dpiNumber from a variable

  • native type DPI_NATIVE_TYPE_NUMBER

  • dpiNumber struct with 22 bytes

  • asNumber variant for dpiDataBuffer. It does not increase sizeof(dpiDataBuffer).

  • dpiData_getNumber and dpiData_setNumber

  • dpiDataBuffer__fromOracleNumberAsNumber

  • dpiDataBuffer__toOracleNumberFromNumber

  • dpiOci__numberAssign wraps OCINumberAssign

  • dpiVar now reads and writes data of native type DPI_NATIVE_TYPE_NUMBER.

Ref #4 .

@anthony-tuininga
Copy link
Member

I will take a look later when I have a bit more time available.

@felipenoris
Copy link
Author

If it would make things easier, I can isolate the arithmetic issue in a separate commit, since this is the only non-working portion of this development.

@tgulacsi
Copy link

tgulacsi commented Mar 4, 2019

I'm a C noob, but can you use a pointer to some value-received structs?
In "dpiNumber_add(const dpiNumber number1, const dpiNumber number2, dpiNumber *result)" but use it as "dpiOci__numberAdd(&error, &number1, &number2, result)".

Why not *dpiNumber all the way up?

@felipenoris
Copy link
Author

felipenoris commented Mar 4, 2019

Yes, that was my first attempt btw. I'll just revert to that and separate the commits.

To answer your question, I did this because I can't make this function call to work, so I tried an alternative. This is the non-working part of the commit.

@felipenoris
Copy link
Author

felipenoris commented Mar 4, 2019

So, for the sake of simplicity, I removed all non-working parts of the commit at https://github.com/felipenoris/odpi/tree/fn/numeric, which are related to dpiNumber arithmetic.

With this, the patch will only expose a dpiNumber. This is already useful because users can convert dpiNumber to other formats directly from the binary format, instead of having to rely on an intermediate string format.

I also updated the first post of this issue.

@felipenoris
Copy link
Author

@anthony-tuininga , please let me know if you need anything else on this.

@anthony-tuininga
Copy link
Member

@felipenoris, I don't think I need anything else. Thanks. I'm not sure when this will be implemented. As you're likely aware there are other priorities!

@acautin
Copy link

acautin commented Aug 5, 2019

@anthony-tuininga this would be helpful as for me as I am trying to work with a database explorer which uses erlang/odpi as the driver in erlang. Precision is lost on the way out and I am trying to understand if this is a limitation of odpi or the erlang driver on top of it.

Do you have an example reading numeric values similar to SELECT 2.700000000000005 FROM dual with full precision ?. (text or otherwise).

@anthony-tuininga
Copy link
Member

@acautin, you can tell ODPI-C to fetch the data as a string representation of the OCI number instead of a double precision floating point number (the default). You can see this happening in the sample. If you create variables instead (by calling dpiConn_newVar()), then make sure the nativeTypeNum parameter is set to DPI_NATIVE_TYPE_BYTES. Either of these methods will return a string representation of the OCI decimal number without any loss of precision.

@felipenoris
Copy link
Author

Hi @anthony-tuininga ! Long time!
I would like to ask if it is possible for you to take a look at this.
See commit felipenoris@3204a05 . The idea is to just expose a dpiNumber struct.

@anthony-tuininga
Copy link
Member

Yes, it has been a while! The commit you reference seems to be simply exposing the 22 bytes of data -- which are in a format that is not easily consumed. How do you intend to consume and generate those 22 bytes of data?

@felipenoris
Copy link
Author

@anthony-tuininga thanks for the reply!

The idea is to let driver developers to access the raw 22 bytes of OraNumber, instead of having to rely on the string representation to get the exact fixed decimal representation.

Obviously the driver developer has to parse these 22 bytes.

I'm already doing this in Oracle.jl. These bytes are loaded into this 22-bytes struct:

struct OraNumber <: Real
    len::UInt8
    ex::UInt8
    mantissa::NTuple{MAX_SIZEOF_MANTISSA, UInt8}
end

From that, I can either implement an API around this struct, or translate to other fixed decimal format.

Hopefully, using these 22-bytes directly is faster than converting from a string representation.

@anthony-tuininga
Copy link
Member

One possibility that might make sense: instead of targeting OCINumber directly, I could add a new "native type" called DPI_NATIVE_TYPE_OCI which simply provides access to the OCI value directly. You can use it for OCINumber but it could be used for other types as well in the future, if that proves useful. I might also expose methods to convert OCINumber to double and text, simply for testing purposes. I believe that should work for you but comments are welcome!

@felipenoris
Copy link
Author

@anthony-tuininga, yes, I think that works, as long as it returns a copy of the data and not a volatile reference in memory. The dpiNumber struct I created was just an auxiliary struct for transferring OCINumber to/from ODPI-C.

@anthony-tuininga
Copy link
Member

I'm not sure what you mean by "volatile reference in memory". The 22 bytes will be stored in the variable buffers and dpiDataBuffer.asOci will be a pointer to that buffer. I believe that's what you meant but can you confirm?

@felipenoris
Copy link
Author

felipenoris commented Feb 25, 2020

@anthony-tuininga , yes I think that works. I'm sure you understand the internals of OCI better than I do. I had to rely on OCINumberAssign to copy the data in a dpiData field so that I could access the data (also setting isNull information on dpiData). I understand that what you're suggesting is a more general approach.

If I select the native type DPI_NATIVE_TYPE_OCI how will I know that it will return a OCINumber and not other data structure? (possible answer: by combining with the information on the Oracle Type + Native Type) ?

@anthony-tuininga
Copy link
Member

If I select the native type DPI_NATIVE_TYPE_OCI how will I know that it will return a OCINumber and not other data structure? (possible answer: by combining with the information on the Oracle Type + Native Type) ?

Yes, you would look at the Oracle Type to determine what actual value you are examining.

@felipenoris
Copy link
Author

@anthony-tuininga that would be awesome!

@tgulacsi
Copy link

Hi,

Go's database/sql seems to get support for decimal handling: golang/go#30870 (comment)

Which means I'm interested in getting/setting OCINumbers directly.

@cjbj
Copy link
Member

cjbj commented Oct 28, 2020

Go's database/sql seems to get support for decimal handling: golang/go#30870 (comment)

Neat!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants