From: Andy C. <an...@ad...> - 2001-04-28 12:36:37
|
Last year I had trouble getting isc_expand_dpb() to work. It turns out = that it CAN'T work as described in the manual. The problems are in the = interface, not in the code. What's wrong with isc_expand_dpb() -=20 [1] There is a difference between the size of a buffer and the size of = the data in the buffer. The API says that isc_expand_dpb() allocates a = new buffer if the new material will not fit into the old buffer. = However, the length parameter is the size of the data in the buffer; = isc_expand_dbp() has no way of knowing how big the old buffer is.=20 [2] The API says that isc_expand_dpb() allocates a new buffer if it = needs it. However, there is nothing said about what happens to the old = buffer. There is no deallocation of the old buffer. Because these flaws are in the functional specs of isc_expand_dpb(), and = not in the code itself, I propose to repair them by providing two new = functions: isc_fill_dpb() takes exactly four parameters: A pointer to a DBP. Before the first call to isc_fill_dbp(), the = caller should set this pointer to NULL. isc_fill_dbp() will do all = allocating of the dbp buffer. A pointer to a short int giving the length of the data in the = dbp_buffer. This is purely an output of isc_fill_dpb(), and is provided = solely for compatablity with isc_attach_database(), which needs this = number as a parameter. A parameter code for the string that is to be inserted into the dbp. A pointer to the string that is to be inserted into the dbp. Note that isc_fill_dbp() does not take variable arguments, like = isc_expand_dpb(). Variable arguments must bypass compile-time type = checking, and thus are error-prone. isc_free_dpb() takes exactly one parameter, the pointer to the DPB as = created and filled by isc_fill_dbp(). This must be called AFTER the call = to isc_attach_database, to release the memory in the buffer. Code calling these function would look like this: char * username =3D ...; char * password =3D ...; char * dpb =3D NULL; short dbp_length; isc_fill_dpb( & dpb, & dpb_length, isc_dpb_user_name, username ); isc_fill_dpb( & dpb, & dpb_length, isc_dpb_password, password ); isc_attach_database( & status_vector, strlen( dbname ), dbname,=20 & dbhandle, dpb_length, dbp ); isc_free_dpb( dbp ); To implement this we would need a new dpb code which the caller never = sees and which marks the allocated length of the dpb and the actual data = length of the dbp (two numbers). Because shorts look a lot smaller now = than they did a few years ago, I'd like to make these four byte numbers. = Therefore the length information block would be ten bytes: one byte for isc_dpb_length one byte with the value 9 a four byte unsigned integer, the allocated length, standard (VAX?) = format a four byte unsigned integer, the data length, in standard (VAX?) = format I believe that this implementation meets the following criteria: * It constructs a dbp which, with the exception of the new = isc_dpb_length field, is completely compatable with the existing dpb = format. I am led to understand that isc_attach_database() ignores any = dpb code that it doesn't understand; therefore it will ignore the = isc_dpb_length code and work as before. * It can be fully thread-friendly. The application can construct two = dbp's at the same time, interleaving the calls to isc_fill_dbp() at = will, with no clash of buffer. * There is no memory leak (unless the caller forgets the call to = isc_free_dpb()). No matter how many times the caller calls = isc_free_dbp(), no matter how many times isc_free_dbp() must re-allocate = the dbp buffer; because isc_free_dpb() knows how the buffer was = allocated, it will free it whenever it must replace it. * with fixed parameters to isc_free_dpb(), not variable parameters, we = have type checking on the code. * When we wish to, we can cause isc_attach_database to store the = dpb_length in an unsigned long integer, and recognize the isc_dpb_length = code, updating the (small) number it received from the caller with the = (large) number it finds in the dbp itself. When we do this we will no = longer be limited to 32767 bytes in the dbp.=20 I am a little concerned that the length of a string in the dbp buffer is = limited to 255 characters by the use of one byte as a length byte; file = names under Windows 98 are limited to 32,767 bytes. If the user calls = isc_fill_dpb() to put the strings into the dbp, we can set the format = code to "2" and make the upgrade invisible to the caller. Of course we need to keep isc_expand_dpb() in the API to support old = code; however we should discourage it's use for new code and shift over = to the new functions. Users would be warned that they can use = isc_fill_dbp() and isc_free_dpb(), or they can do it themselves, but = they should not mix methods as isc_fill_dpb() is not guaranteed to = follow the format given in the API. I welcome any comments. According to the API, isc_expand_dpb() and = isc_attach_database() are the only two functions that use the dbp at = all. But there is a TPB - maybe we should make the code handle both? How = does this fix fit in with plans that others have? |