[ruby-oci8-devel] [Ruby-oci8-devel] alloc_sz

Liming Lian liming.lian at oracle.com
Mon Dec 10 05:19:52 EST 2007


Hi Kubo,

Thanks for your reply!

By hacking the code, I am glad to see a lot of efforts have been done 
for preparing the implementation of Array DML. I notice following 
variable: max_array_size, the magic switch for entering array insert 
mode. By passing a non-null max_array_size parameter to 
oci8_bind_initialize, the array insert mode is switched on. The program 
will check the input binding variable of array type, and then allocate 
necessary memory, assign element values to the right positions by using 
oci8_set_data and oci8_set_data_at, and finally call the OCIBindByPos or 
OCIBindByName to finish the binding task.

One thing I want to make clear is, kubo, which kind of binds are you 
initially considering to support for Array DML? OCI supports two kinds 
of binds for array DML, PL/SQL binds and non-PL/SQL binds.

PHP has implemented a function, oci_bind_array_by_name, which implements 
the PL/SQL binds for array DML. Check more at 
http://us2.php.net/manual/en/function.oci-bind-array-by-name.php. While 
Perl's bind_param_array is to implement non-PL/SQL binds.

If I don't remember wrong, for OCIBindByPos or OCIBindByName, once you 
have passed non-null values to parameters maxarr_len and curelep, OCI 
assumes it is a PL/SQL bind. So if we want to implement non-PL/SQL, both 
maxarr_len and curelep should be set NULL. Otherwise OCI will report 
following error: ORA-01484: arrays can only be bound to PL/SQL statements.

Please look at the function call for OCIBindByPos in oci8_bind of file 
stmt.c.

if (obind->maxar_sz == 0) {
curelep = NULL;
} else {
curelep = &obind->curar_sz;
}

And,

status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, 
oci8_errhp, position, obind->valuep, obind->value_sz, bind_class->dty, 
indp, NULL, 0, obind->maxar_sz, curelep, mode);


It means that once we have set maxar_sz, both parameters: maxarr_len and 
curelep will be enabled in the OCIBindByPos call. So from the source 
code, I guess it is to implement the PL/SQL binds.


> Hi Liming,
>
>   
>>     sz += sizeof(sb4);
>>     obind->value_sz = sz;
>>     obind->alloc_sz = (sz + (sizeof(sb4) - 1)) & ~(sizeof(sb4) - 1);
>>     
>
> This round up to sz to 4-byte boundary.
>   If sz is 5~8, alloz_sz is 8. If 9~12, 12.
>
> (sz + (sizeof(sb4) - 1)) & ~(sizeof(sb4) - 1)
>   => (sz + (4 - 1) & ~(4 - 1)
>   => (sz + 3) & ~3
>   => (sz + 3) & 0xFFFFFFFC
>
> round-up is done by one addition and one bit-mask. This is most
> efficient way.
>
> sizeof(sb4) is 4 in any OS and CPU. We can write more simply as
> "(sz + 3) & 0xFFFFFFFC". But if sizeof(x)'s value depends on OS or
> CPU, "(sz + (sizeof(x) - 1)) & ~(sizeof(x) - 1)" is most portable.
> This is an idiom in C.
>
>   
>> I am wondering why the alloc_sz is calculated from the above expression,
>> any hints? I want to make this clear because this attribute will be used
>> for allocating memory for binding value and passed to
>> OCIBindArrayOfStruct as skip parameter later.
>>     
>
> The first member of oci8_vstr_t is sb4. It should be aligned to 4-byte
> boundary in memory on x86 CPU. If it is not aligned, it causes memory
> access penalty. As for SPARC CPU, it must be aligned, otherwise it
> causes BUS error. If alloc_sz is not a multiple of 4, the second
> element is not on 4-byte boundary.
>
>   



More information about the ruby-oci8-devel mailing list