Re: win64
"Frediano Ziglio" <[email protected]>
| Newsgroups | gmane.comp.db.tds.freetds |
|---|---|
| Message-ID | <[email protected]> |
2009/1/17 James K. Lowden <[email protected]>: > Sometimes work guides The Work. I built FreeTDS for 64-bit Windows this > week with VS 2005. I modified libtds to emit fewer warnings -- I left > some that are pretty egregious -- and added a .sln and .vcproj files to > the src directories. > good.. I would have put in win32 directory but it's ok. > As far as I know, I'm the first one to do this. There was barely any > support for it. For example, the winsock stuff was defined only for > WIN32. It's a big patch. > ??? are you sure ?? Do you know WIN32 is defined even for win64 ?? > What follows are some notes on what I did in case it helps anyone else. > > Win64 is an LLP64 architecture, whereas Linux uses LP64. The major > difference is that a Win64 long integer is still 32 bits while a Linux > long is 64 bits (cf. > http://www.ibm.com/developerworks/library/l-port64.html and > http://www.unix.org/version2/whatsnew/lp64_wp.html). size_t can hold the > maximum difference between two pointers. In Linux, size_t is the same as > an unsigned long. In Win64 there's no standard type equivalent to size_t. > intptr_t perhaps or something like that. There is also TDS_INTPTR ! > > There's an inherent tension in the C standard library between integers and > sizes. For example, strlen(3) returns size_t and sprintf(3) returns int. > To be meaninful, the values being compared have to fit within both > datatype's domains (which typically they do, but the compiler can't know > that and the handling of the atypical case will likely hurt). . > > To squelch the warnings, we add a cast. To be safe, that cast really > should be inside a conversion function that uses assert(3) to verify the > size_t values fits in 31 bits. I didn't do that, but it would be IMO a > worthwhile exercise. > > Simlilarly, libtds plays fast and loose with int and unsigned int. Most > of the time it's really OK: how often will a column name length need more > than 2^31 bits? I find myself wondering if we shouldn't have a function > strleni() that returns an int after checking the size. . > > Another way to handle this would be to make widespread use of a union, > > typedef union tds_length { > unsigned long ulong; > size_t size; > int len; > } TDS_LENGTH; > > and use checking functions (or macros) > > size_t > as_size( TDS_LENGTH L ) > { > assert(L.len > 0); > return L.size; > } > > int > as_int( TDS_LENGTH L ) > { > assert(L.size <= INT_MAX); > return L.len; > } > > unsigned long > as_ulong( TDS_LENGTH L ) > { > assert(L.len > 0); > return L.ulong; > } > > to write such code as > > TDS_LENGTH a; > a.len = sprintf(...); > if( as_size(a) != strlen(...) ) > return FAIL; > it can't work !!! Think about endianess !!! > That would constrain TDS_LENGTH to use values <= 2^31 is most cases. The > functions *assume* you're using the structure for type-punning. Short of > C++'s operator overloading, there's no easy way to check. > > There are many places in libtds particularly where int is used where > size_t would have been more in keeping with the standard library. (I'm as > guilty as anyone else; old habits are hard to break.) Often, the type is > chosen to match a corresponding part of the TDS data strea, e.g. > TDSRESULTINFO::row_size is TDS_INT because that's how column widths are > defined in the TDS_ROWFMT2 packet. (But it's not used that way in > practice. tds_alloc_row() defines its local row_size as TDS_UINT, > accumulates the sizes of the columns, and assigns the sum to > TDSRESULTINFO::row_size. It would have been better to use size_t after > all.) > Ok, size_t is correct, however see how packet is readed from network and how row is allocated. Column number is a 16 bit so there can be at maximun 2^16 = 65536 columns so each column can contains up to 2^31 / 2^16 = 2^15. Considering that BLOBs occupy just few bytes and variable columns occupy at maximun 8000 bytes... there is no limit... 31 bits are sufficient for every rowset. > I think it would be better to use standard C types within the library and > as much as possible reserve casts to deal with TDS packets or API calls. > I wonder what others have done. It's not an easy question to research. > Personally I think this patch it too big and contains a lot of changes grouped in a single one: - new defines for sybdb.h just to make some windows programs happy... nothing related to win64 - use of newer _fseeki64 which break compatibility with old VS and even mingw - changed inclusion styles. Are you sure that client programs works as expected ?? - a lot of warning removed just adding casts - added a log and a strange string copy in tds_put_login_string (with a possible buffer overflow... I'll check it) - winsocket initialization (why in mem.c and not in net.c ??) - other minor styles changes freddy77