Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 18, 2015 Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
By the use of this tutorial (http://www.easysoft.com/developer/languages/c/odbc_tutorial.html), I thought it would be very straightforward to use etc.c.odbc.sqlext and etc.c.odbc.sql to create a simple odbc application. But as soon as I started, I noticed a quirk: SQLRETURN ret; SQLHDBC dbc; ret = SQLDriverConnect(dbc, null, "DNS=*mydns*;", SQL_NTS, null, 0, null, SQL_DRIVER_COMPLETE); This gives me an error: function etc.c.odbc.sqlext.SQLDriverConnect (void* hdbc, void* hwnd, char* szConnStrIn, short cbConnStrIn, char* szConnStrOut, short cbConnStrOutMax, short* pcbConnStrOut, ushort fDriverCompletion) is not callable using argument types (void*, typeof(null), string, int, typeof(null), int, typeof(null), int) After some casting, I found out it's all related to the string literal. I thought it would work straight off the box, after reading the "Interfacing to C" spec (http://dlang.org/spec/interfaceToC.html). When I remove the string literal and replace it with null, it compiles. .ptr and .toStringz both give immutable char* references, and don't work. A "cast(char *)"DNS=*maydns*;"" works, but it feels a lot like a hack that will not work in the long run. |
December 18, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Fer22f | On Friday, 18 December 2015 at 22:14:04 UTC, Fer22f wrote:
> When I remove the string literal and replace it with null, it compiles. .ptr and .toStringz both give immutable char* references, and don't work. A "cast(char *)"DNS=*maydns*;"" works, but it feels a lot like a hack that will not work in the long run.
That's what the examples on MSDN do too though, a cast. At first I thought the binding was missing a const, but the ODBC docs don't specify it as const either and cast.
So it is kinda weird but I think right according to docs. However, I'd argue we should make it const if it can be...
|
December 18, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Fer22f | On 18.12.2015 23:14, Fer22f wrote:
> By the use of this tutorial
> (http://www.easysoft.com/developer/languages/c/odbc_tutorial.html), I
> thought it would be very straightforward to use etc.c.odbc.sqlext and
> etc.c.odbc.sql to create a simple odbc application. But as soon as I
> started, I noticed a quirk:
>
> SQLRETURN ret;
> SQLHDBC dbc;
> ret = SQLDriverConnect(dbc, null, "DNS=*mydns*;", SQL_NTS,
> null, 0, null, SQL_DRIVER_COMPLETE);
>
> This gives me an error: function etc.c.odbc.sqlext.SQLDriverConnect
> (void* hdbc, void* hwnd, char* szConnStrIn, short cbConnStrIn, char*
> szConnStrOut, short cbConnStrOutMax, short* pcbConnStrOut, ushort
> fDriverCompletion) is not callable using argument types (void*,
> typeof(null), string, int, typeof(null), int, typeof(null), int)
>
> After some casting, I found out it's all related to the string literal.
> I thought it would work straight off the box, after reading the
> "Interfacing to C" spec (http://dlang.org/spec/interfaceToC.html).
>
> When I remove the string literal and replace it with null, it compiles.
> .ptr and .toStringz both give immutable char* references, and don't
> work. A "cast(char *)"DNS=*maydns*;"" works, but it feels a lot like a
> hack that will not work in the long run.
If the parameter is de facto const, then the cast is ok. Though, maybe it should be marked const then.
If the parameter is really not const, i.e. the function may mutate the argument, then the cast is not ok. You can use `.dup.ptr` instead to get a proper char* from a string.
Also, remember that D's GC doesn't scan foreign memory. So if the function keeps the string around, and that's the only reference, then the GC would collect it. The function probably doesn't keep the string around, though.
|
December 19, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to anonymous | On Friday, 18 December 2015 at 22:35:04 UTC, anonymous wrote:
> If the parameter is de facto const, then the cast is ok. Though, maybe it should be marked const then.
I'm just worried about casts because I read somewhere that strings start with the number of characters inside them (probably in slices documentation), and not with actual content (though string literals probably act different in this case).
Documentation on casts say:
Casting a pointer type to and from a class type is done as a type paint (i.e. a reinterpret cast).
Reinterpretation is rather dangerous if strings are stored differently.
But this test gives me a good hope on this case:
writeln(*(cast(char*) "Test"));
Casting is what I'm going with. .dup.ptr is less clear in this case.
|
December 19, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Friday, 18 December 2015 at 22:18:34 UTC, Adam D. Ruppe wrote:
> That's what the examples on MSDN do too though, a cast. At first I thought the binding was missing a const, but the ODBC docs don't specify it as const either and cast.
The ODBC functions also have a size parameter for string parameters. You can set it to SQL_NTS to use the 0 terminated C standard. Might justify on why it's char* instead of const char*.
It looks like it's alright, then. Just one implementation detail I didn't notice before.
|
December 19, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Fer22f | On 19.12.2015 01:06, Fer22f wrote: > Documentation on casts say: > > Casting a pointer type to and from a class type is done as a type paint > (i.e. a reinterpret cast). > That sentence doesn't apply. string is not a class, it's an alias for immutable(char)[], i.e. it's an array. > Reinterpretation is rather dangerous if strings are stored differently. > > But this test gives me a good hope on this case: > > writeln(*(cast(char*) "Test")); > > Casting is what I'm going with. .dup.ptr is less clear in this case. Correctness beats clarity. I'd like to advise you not to use casts unless you know for sure that they're safe. Here, you need to know what a string is exactly, what the cast does exactly, and what exactly the called function does with the pointer. |
December 19, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to anonymous | On Friday, 18 December 2015 at 22:35:04 UTC, anonymous wrote:
> If the parameter is really not const, i.e. the function may mutate the argument, then the cast is not ok. You can use `.dup.ptr` instead to get a proper char* from a string.
As this is going to be passed to a C function, it would need to be zero-terminated. `.dup` doesn't do this, he'd have to use `std.string.toStringz` instead. However, that function returns a `immutable(char)*`, which would have to be cast again :-(
|
December 19, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On 19.12.2015 14:20, Marc Schütz wrote:
> As this is going to be passed to a C function, it would need to be
> zero-terminated. `.dup` doesn't do this, he'd have to use
> `std.string.toStringz` instead. However, that function returns a
> `immutable(char)*`, which would have to be cast again :-(
Ouch, I totally missed that. Looks like we don't have a nice way to do this then?
|
December 19, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | Well, ISO 9075-3 doesn't use const qualifiers, but uses IN/OUT qualifiers instead, e.g. ExecDirect function is declared as: ExecDirect ( StatementHandle IN INTEGER, StatementText IN CHARACTER(L), TextLength IN INTEGER ) RETURNS SMALLINT And in C header: SQLRETURN SQLExecDirect(SQLHSTMT StatementHandle, SQLCHAR *StatementText, SQLINTEGER TextLength); |
December 19, 2015 Re: Problems with string literals and etc.c.odbc.sql functions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Saturday, 19 December 2015 at 13:20:03 UTC, Marc Schütz wrote:
> As this is going to be passed to a C function
No, ODBC API is designed with multilingual capability in mind, it doesn't rely on null terminated strings heavily: all string arguments support length specification.
|
Copyright © 1999-2021 by the D Language Foundation