Re: UNICODE support

Nick Gorham <[email protected]> Mon, 28 Mar 2016 13:22:48 +0100
Newsgroups gmane.comp.db.unixodbc.devel
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--===============1091204469==
Content-Type: multipart/alternative;
	boundary="------------090704020904070004050000"

This is a multi-part message in MIME format.
--------------090704020904070004050000
Content-Type: text/plain; charset=windows-1252; format=flowed
Content-Transfer-Encoding: 7bit

On 28/03/16 01:35, Igor Korot wrote:
> Nick,
>
> On Sat, Mar 26, 2016 at 2:57 PM, Nick Gorham <[email protected]> wrote:
>> On 26/03/16 18:00, Igor Korot wrote:
>>> Nick,
>>>
>>> On Sat, Mar 26, 2016 at 1:36 PM, Nick Gorham <[email protected]> wrote:
>>>> On 26/03/16 17:31, Igor Korot wrote:
>>>>> Hi, Nick,
>>>>>
>>>>> On Sat, Mar 26, 2016 at 12:58 PM, Nick Gorham <[email protected]> wrote:
>>>>>> On 26/03/16 15:10, Igor Korot wrote:
>>>>>>> Hi, (Nick),
>>>>>>> Is it enough to do:
>>>>>>>
>>>>>>> #define UNICODE
>>>>>>>
>>>>>>> in order to use SQLW-types and functions?
>>>>>>>
>>>>>>> Or I need to define something else?
>>>>>>>
>>>>>>> Thank you.
>>>>>>> _______________________________________________
>>>>>>> unixODBC-dev mailing list
>>>>>>> [email protected]
>>>>>>> http://mailman.unixodbc.org/mailman/listinfo/unixodbc-dev
>>>>>> You should just be able to use them. Whats not working?
>>>>> Check the following code:
>>>>>
>>>>> [code]
>>>>> /* odbc.c
>>>>>
>>>>>        testing unixODBC
>>>>> */
>>>>> #include <stdlib.h>
>>>>> #include <stdio.h>
>>>>> #include <odbcinst.h>
>>>>> #include <sqlext.h>
>>>>>
>>>>> #define SQL_WCHART_CONVERT
>>>>>
>>>>> int main(int argc,char *argv[])
>>>>> {
>>>>>        SQLHENV m_henv;
>>>>>        SQLSMALLINT i = 1, attr_ret;
>>>>>        SQLWCHAR driverDesc[1024], driverAttributes[256],
>>>>> dsn[SQL_MAX_DSN_LENGTH + 1], sqlState[20],
>>>>> errMsg[SQL_MAX_MESSAGE_LENGTH], dsnDescr[255];
>>>>>        SWORD pcbDSN, pcbDesc;
>>>>>        SQLINTEGER nativeError;
>>>>>        SQLSMALLINT cbErrorMsg, descriptionLength;
>>>>>        SQLUSMALLINT direction = SQL_FETCH_FIRST, direct =
>>>>> SQL_FETCH_FIRST;
>>>>>
>>>>>        RETCODE ret = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HENV,
>>>>> &m_henv
>>>>> );
>>>>>        if( ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO )
>>>>>        {
>>>>>            printf( "Error allocating handle\r\n" );
>>>>>            while( ( ret = SQLGetDiagRecW( SQL_HANDLE_ENV, m_henv, i,
>>>>> sqlState, &nativeError, errMsg, sizeof( errMsg ), &cbErrorMsg ) ) ==
>>>>> SQL_SUCCESS )
>>>>>            {
>>>>>                printf( "Error is: %s\r\n", errMsg );
>>>>>            }
>>>>>            exit( 0 );
>>>>>        }
>>>>>        else
>>>>>        {
>>>>>            ret = SQLSetEnvAttr( m_henv, SQL_ATTR_ODBC_VERSION, (void *)
>>>>> SQL_OV_ODBC3, 0 );
>>>>>            if( ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO )
>>>>>            {
>>>>>                printf( "Error setting environment\r\n" );
>>>>>                while( ( ret = SQLGetDiagRec( SQL_HANDLE_ENV, m_henv, i,
>>>>> sqlState, &nativeError, errMsg, sizeof( errMsg ), &cbErrorMsg ) ) ==
>>>>> SQL_SUCCESS )
>>>>>                {
>>>>>                    printf( "Error is: %s\r\n", errMsg );
>>>>>                }
>>>>>                exit( 0 );
>>>>>            }
>>>>>            else
>>>>>            {
>>>>>                while( ( ret = SQLDrivers( m_henv, direction, driverDesc,
>>>>> sizeof( driverDesc ) - 1, &descriptionLength, driverAttributes,
>>>>> sizeof( driverAttributes ), &attr_ret ) ) == SQL_SUCCESS )
>>>>>                {
>>>>>                    while( ( ret = SQLDataSources( m_henv, direct, dsn,
>>>>> SQL_MAX_DSN_LENGTH, &pcbDSN, dsnDescr, 254, &pcbDesc ) ) ==
>>>>> SQL_SUCCESS )
>>>>>                    {
>>>>>                        printf( "Driver description is %s", driverDesc );
>>>>>                        printf( "DSN description is %s", dsnDescr );
>>>>>                        direct = SQL_FETCH_NEXT;
>>>>>                    }
>>>>>                    if( ret != SQL_SUCCESS && ret != SQL_NO_DATA )
>>>>>                    {
>>>>>                        printf( "Error retrieving Data Source" );
>>>>>                        while( ( ret = SQLGetDiagRec( SQL_HANDLE_ENV,
>>>>> m_henv, i, sqlState, &nativeError, errMsg, sizeof( errMsg ),
>>>>> &cbErrorMsg ) ) == SQL_SUCCESS )
>>>>>                        {
>>>>>                            printf( "Error is: %s\r\n", errMsg );
>>>>>                        }
>>>>>                        break;
>>>>>                    }
>>>>>                    direction = SQL_FETCH_NEXT;
>>>>>                }
>>>>>            }
>>>>>        }
>>>>>        return 0;
>>>>> }
>>>>> [/code]
>>>>>
>>>>> resulted in:
>>>>>
>>>>> [code]
>>>>> igor@IgorDellGentoo ~ $ gcc -DUNICODE odbctest.cpp -o odbctest -lodbc
>>>>> odbctest.cpp: In function 'int main(int, char**)':
>>>>> odbctest.cpp:30:48: warning: format '%s' expects argument of type
>>>>> 'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
>>>>> [-Wformat=]
>>>>>                 printf( "Error is: %s\r\n", errMsg );
>>>>>                                                    ^
>>>>> odbctest.cpp:42:52: warning: format '%s' expects argument of type
>>>>> 'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
>>>>> [-Wformat=]
>>>>>                     printf( "Error is: %s\r\n", errMsg );
>>>>>                                                        ^
>>>>> odbctest.cpp:52:68: warning: format '%s' expects argument of type
>>>>> 'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
>>>>> [-Wformat=]
>>>>>                         printf( "Driver description is %s", driverDesc );
>>>>>                                                                        ^
>>>>> odbctest.cpp:53:63: warning: format '%s' expects argument of type
>>>>> 'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
>>>>> [-Wformat=]
>>>>>                         printf( "DSN description is %s", dsnDescr );
>>>>>                                                                   ^
>>>>> odbctest.cpp:61:60: warning: format '%s' expects argument of type
>>>>> 'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
>>>>> [-Wformat=]
>>>>>                             printf( "Error is: %s\r\n", errMsg );
>>>>>                                                                ^
>>>>> [/code]
>>>>>
>>>>> Any idea what is going on? And how to fix it?
>>>>>
>>>>> Thank you.
>>>>
>>>> Err, I think the compiler is telling you, You have a array
>>>>
>>>> SQLWCHAR errMsg[SQL_MAX_MESSAGE_LENGTH]
>>> Well I do have "-DUNICODE" passed to the compiler.
>>> So SQLWCHAR should not become "unsigned char", but rather "wchar_t".
>>>
>>> Am I wrong?
>>>
>>> Thank you.
>>
>> Yes.
>>
>> SQLWCHAR that ODBC uses is a 16 byte type, wchar_t is normally a 32 byte
>> type.
>>
>> I think you may be thinking of SQLTCHAR that will switch between char and
>> SQLWCHAR depending on the flag. But either way, the standard library
>> (printf) doesn't know or care, %s = char
> Taken from  C:\Program Files (x86)\Microsoft
> SDKs\Windows\v7.0A\Include\sqltypes.h(286:
>
> [code]
> #ifdef _WCHAR_T_DEFINED
> typedef wchar_t SQLWCHAR;
> #else
> typedef unsigned short SQLWCHAR;
> #endif
>
> #ifdef UNICODE
> typedef SQLWCHAR        SQLTCHAR;
> #else
> typedef SQLCHAR         SQLTCHAR;
> #endif  /* UNICODE */
> [/code]
>
> I presume unixODBC uses the same code, right?
>
> Which means that all I need is to define _WCHAR_T_DEFINED in order for SQLWCHAR
> to become wchar_t instead of unsigned short.

Generally, no. To quote "/|wchar_t| is compiler-dependent and therefore 
not very portable. Using it for Unicode binds a program to the character 
model of a compiler. Instead, it is often better to define and use 
dedicated data types."

/In most cases outside of Windows wchar_t is a 4 byte type. You can 
build unixODBC to use 4 byte SQLWCHAR, but you will find it won't work 
with most drivers out there. /
/
>
> Now on  related note, char = %c char* = %s, is it not?
> Granted I didn't use plain C for a long time, but I think here I'm right. ;-)

Yes, I was assuming a shorthand, where %s is char array, I assumed you 
would know the array part. But the important part of that is that its 
char, not long, short or int.

-- 
Nick

--------------090704020904070004050000
Content-Type: text/html; charset=windows-1252
Content-Transfer-Encoding: 7bit

<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <div class="moz-cite-prefix">On 28/03/16 01:35, Igor Korot wrote:<br>
    </div>
    <blockquote
cite="mid:CA+FnnTxGqC-wipS6SDNLmTTi=9VC=OxG6xR-HWNfHVHxo0aMTg@mail.gmail.com"
      type="cite">
      <pre wrap="">Nick,

On Sat, Mar 26, 2016 at 2:57 PM, Nick Gorham <a class="moz-txt-link-rfc2396E" href="mailto:[email protected]">&lt;[email protected]&gt;</a> wrote:
</pre>
      <blockquote type="cite">
        <pre wrap="">On 26/03/16 18:00, Igor Korot wrote:
</pre>
        <blockquote type="cite">
          <pre wrap="">
Nick,

On Sat, Mar 26, 2016 at 1:36 PM, Nick Gorham <a class="moz-txt-link-rfc2396E" href="mailto:[email protected]">&lt;[email protected]&gt;</a> wrote:
</pre>
          <blockquote type="cite">
            <pre wrap="">
On 26/03/16 17:31, Igor Korot wrote:
</pre>
            <blockquote type="cite">
              <pre wrap="">
Hi, Nick,

On Sat, Mar 26, 2016 at 12:58 PM, Nick Gorham <a class="moz-txt-link-rfc2396E" href="mailto:[email protected]">&lt;[email protected]&gt;</a> wrote:
</pre>
              <blockquote type="cite">
                <pre wrap="">
On 26/03/16 15:10, Igor Korot wrote:
</pre>
                <blockquote type="cite">
                  <pre wrap="">
Hi, (Nick),
Is it enough to do:

#define UNICODE

in order to use SQLW-types and functions?

Or I need to define something else?

Thank you.
_______________________________________________
unixODBC-dev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
<a class="moz-txt-link-freetext" href="http://mailman.unixodbc.org/mailman/listinfo/unixodbc-dev">http://mailman.unixodbc.org/mailman/listinfo/unixodbc-dev</a>
</pre>
                </blockquote>
                <pre wrap="">
You should just be able to use them. Whats not working?
</pre>
              </blockquote>
              <pre wrap="">
Check the following code:

[code]
/* odbc.c

      testing unixODBC
*/
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;odbcinst.h&gt;
#include &lt;sqlext.h&gt;

#define SQL_WCHART_CONVERT

int main(int argc,char *argv[])
{
      SQLHENV m_henv;
      SQLSMALLINT i = 1, attr_ret;
      SQLWCHAR driverDesc[1024], driverAttributes[256],
dsn[SQL_MAX_DSN_LENGTH + 1], sqlState[20],
errMsg[SQL_MAX_MESSAGE_LENGTH], dsnDescr[255];
      SWORD pcbDSN, pcbDesc;
      SQLINTEGER nativeError;
      SQLSMALLINT cbErrorMsg, descriptionLength;
      SQLUSMALLINT direction = SQL_FETCH_FIRST, direct =
SQL_FETCH_FIRST;

      RETCODE ret = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HENV,
&amp;m_henv
);
      if( ret != SQL_SUCCESS &amp;&amp; ret != SQL_SUCCESS_WITH_INFO )
      {
          printf( "Error allocating handle\r\n" );
          while( ( ret = SQLGetDiagRecW( SQL_HANDLE_ENV, m_henv, i,
sqlState, &amp;nativeError, errMsg, sizeof( errMsg ), &amp;cbErrorMsg ) ) ==
SQL_SUCCESS )
          {
              printf( "Error is: %s\r\n", errMsg );
          }
          exit( 0 );
      }
      else
      {
          ret = SQLSetEnvAttr( m_henv, SQL_ATTR_ODBC_VERSION, (void *)
SQL_OV_ODBC3, 0 );
          if( ret != SQL_SUCCESS &amp;&amp; ret != SQL_SUCCESS_WITH_INFO )
          {
              printf( "Error setting environment\r\n" );
              while( ( ret = SQLGetDiagRec( SQL_HANDLE_ENV, m_henv, i,
sqlState, &amp;nativeError, errMsg, sizeof( errMsg ), &amp;cbErrorMsg ) ) ==
SQL_SUCCESS )
              {
                  printf( "Error is: %s\r\n", errMsg );
              }
              exit( 0 );
          }
          else
          {
              while( ( ret = SQLDrivers( m_henv, direction, driverDesc,
sizeof( driverDesc ) - 1, &amp;descriptionLength, driverAttributes,
sizeof( driverAttributes ), &amp;attr_ret ) ) == SQL_SUCCESS )
              {
                  while( ( ret = SQLDataSources( m_henv, direct, dsn,
SQL_MAX_DSN_LENGTH, &amp;pcbDSN, dsnDescr, 254, &amp;pcbDesc ) ) ==
SQL_SUCCESS )
                  {
                      printf( "Driver description is %s", driverDesc );
                      printf( "DSN description is %s", dsnDescr );
                      direct = SQL_FETCH_NEXT;
                  }
                  if( ret != SQL_SUCCESS &amp;&amp; ret != SQL_NO_DATA )
                  {
                      printf( "Error retrieving Data Source" );
                      while( ( ret = SQLGetDiagRec( SQL_HANDLE_ENV,
m_henv, i, sqlState, &amp;nativeError, errMsg, sizeof( errMsg ),
&amp;cbErrorMsg ) ) == SQL_SUCCESS )
                      {
                          printf( "Error is: %s\r\n", errMsg );
                      }
                      break;
                  }
                  direction = SQL_FETCH_NEXT;
              }
          }
      }
      return 0;
}
[/code]

resulted in:

[code]
igor@IgorDellGentoo ~ $ gcc -DUNICODE odbctest.cpp -o odbctest -lodbc
odbctest.cpp: In function 'int main(int, char**)':
odbctest.cpp:30:48: warning: format '%s' expects argument of type
'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
[-Wformat=]
               printf( "Error is: %s\r\n", errMsg );
                                                  ^
odbctest.cpp:42:52: warning: format '%s' expects argument of type
'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
[-Wformat=]
                   printf( "Error is: %s\r\n", errMsg );
                                                      ^
odbctest.cpp:52:68: warning: format '%s' expects argument of type
'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
[-Wformat=]
                       printf( "Driver description is %s", driverDesc );
                                                                      ^
odbctest.cpp:53:63: warning: format '%s' expects argument of type
'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
[-Wformat=]
                       printf( "DSN description is %s", dsnDescr );
                                                                 ^
odbctest.cpp:61:60: warning: format '%s' expects argument of type
'char*', but argument 2 has type 'SQLWCHAR* {aka short unsigned int*}'
[-Wformat=]
                           printf( "Error is: %s\r\n", errMsg );
                                                              ^
[/code]

Any idea what is going on? And how to fix it?

Thank you.
</pre>
            </blockquote>
            <pre wrap="">

Err, I think the compiler is telling you, You have a array

SQLWCHAR errMsg[SQL_MAX_MESSAGE_LENGTH]
</pre>
          </blockquote>
          <pre wrap="">
Well I do have "-DUNICODE" passed to the compiler.
So SQLWCHAR should not become "unsigned char", but rather "wchar_t".

Am I wrong?

Thank you.
</pre>
        </blockquote>
        <pre wrap="">

Yes.

SQLWCHAR that ODBC uses is a 16 byte type, wchar_t is normally a 32 byte
type.

I think you may be thinking of SQLTCHAR that will switch between char and
SQLWCHAR depending on the flag. But either way, the standard library
(printf) doesn't know or care, %s = char
</pre>
      </blockquote>
      <pre wrap="">
Taken from  C:\Program Files (x86)\Microsoft
SDKs\Windows\v7.0A\Include\sqltypes.h(286:

[code]
#ifdef _WCHAR_T_DEFINED
typedef wchar_t SQLWCHAR;
#else
typedef unsigned short SQLWCHAR;
#endif

#ifdef UNICODE
typedef SQLWCHAR        SQLTCHAR;
#else
typedef SQLCHAR         SQLTCHAR;
#endif  /* UNICODE */
[/code]

I presume unixODBC uses the same code, right?

Which means that all I need is to define _WCHAR_T_DEFINED in order for SQLWCHAR
to become wchar_t instead of unsigned short.</pre>
    </blockquote>
    <br>
    Generally, no. To quote "<em><code>wchar_t</code> is
      compiler-dependent and therefore not very portable. Using it for
      Unicode binds a program to the character model of a compiler.
      Instead, it is often better to define and use dedicated data
      types."<br>
      <br>
    </em>In most cases outside of Windows wchar_t is a 4 byte type. You
    can build unixODBC to use 4 byte SQLWCHAR, but you will find it
    won't work with most drivers out there. <em><br>
    </em>
    <blockquote
cite="mid:CA+FnnTxGqC-wipS6SDNLmTTi=9VC=OxG6xR-HWNfHVHxo0aMTg@mail.gmail.com"
      type="cite">
      <pre wrap="">

Now on  related note, char = %c char* = %s, is it not?
Granted I didn't use plain C for a long time, but I think here I'm right. ;-)</pre>
    </blockquote>
    <br>
    Yes, I was assuming a shorthand, where %s is char array, I assumed
    you would know the array part. But the important part of that is
    that its char, not long, short or int.<br>
    <br>
    -- <br>
    Nick<br>
  </body>
</html>

--------------090704020904070004050000--

--===============1091204469==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
unixODBC-dev mailing list
[email protected]
http://mailman.unixodbc.org/mailman/listinfo/unixodbc-dev

--===============1091204469==--