[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