Skip Menu |
 

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the DBD-Oracle CPAN distribution.

Report information
The Basics
Id: 6560
Status: resolved
Priority: 0/
Queue: DBD-Oracle

People
Owner: Nobody in particular
Requestors: bai [...] dreamarts.co.jp
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 1.15
Fixed in: (no value)

Attachments
DBD-Oracle-1.15-lob.patch



Subject: BLOB/CLOB memory leak patch
Download (untitled) / with headers
text/plain 1.5k
Package: DBD-Oracle-1.15 Environment: perl-5.6.0, i386-linux 2.4.7-2.24ml, Oracle-8.1.7 Description: When using Oracle BLOB from within mod_perl, we found the size of httpd process increasing. If you changes BLOB to LONGRAW, there will be no memory increasing. Our module using DBI-1.41 and DBD-Oracle-1.15, and just "simple LOB" were used. Reproduce Steps: 1) Create a table on Oracle: CREATE TABLE lob (id INTEGER PRIMARY KEY, object_data BLOB) 2) Using following trivial snippet to insert binary as BLOB for 1000 times: sub insert($$$) { my ($dbh, $id, $object) = @_; my $sql = "INSERT INTO lob(id, object_data) VALUES (?, ?)"; my $sth = $dbh->prepare($sql); $sth->bind_param(1, $id); $sth->bind_param(2, $object, {ora_type => ORA_BLOB}); my $rv = $sth->execute(); $sth->finish(); } A binary file about 2KB was used in our test. 3) You can observe at a "top" console that the memory usage increasing at about 4096 bytes per insert call. Patch: It spent 2 days to dig it, all leaks are in oci8.c, inside function init_lob_refetch() and ora_free_lob_refetch(), leaks happened in XSUB and OCI calls. By the experiences on XSUB and OCI, it is possible for me to contribute a "LOB leak" patch. The patch has been tested on both "simple LOB" and "Using Locator" pattern, both "INSERT" and "UPDATE" operations. For "Using Locator" INSERT/UPDATE test examples, just see author Tim Bunce's detailed document: http://search.cpan.org/~timb/DBD-Oracle-1.15/Oracle.pm, section "Handling LOBs". Dongqiang Bai 2004-06-09
diff -Naur DBD-Oracle-1.15/oci8.c DBD-Oracle-1.15-patch/oci8.c --- DBD-Oracle-1.15/oci8.c Sat Jan 10 09:00:34 2004 +++ DBD-Oracle-1.15-patch/oci8.c Wed Jun 9 10:25:41 2004 @@ -1491,7 +1491,7 @@ ++src; *len = src - start; if (copy) { - p = alloc_via_sv(*len, 0, 1); + p = (char *)malloc((*len) + 1); strncpy(p, start, *len); p[*len] = '\0'; return p; @@ -1581,6 +1581,7 @@ strcpy(new_tablename, syn_schema); strcat(new_tablename, "."); strcat(new_tablename, syn_name); + free(tablename); tablename=new_tablename; if (DBIS->debug >= 3) PerlIO_printf(DBILOGFP, " lob refetch synonym, schema=%s, name=%s, new tablename=%s\n", syn_schema, syn_name, tablename); @@ -1595,6 +1596,8 @@ (ub1)OCI_OTYPE_NAME, (ub1)1, (ub1)OCI_PTYPE_VIEW, dschp, status); if (status != OCI_SUCCESS) { OCIHandleFree_log_stat(dschp, OCI_HTYPE_DESCRIBE, status); + if (tablename != new_tablename) + free(tablename); return oci_error(sth, errhp, status, "OCIDescribeAny(view)/LOB refetch"); } } @@ -1611,6 +1614,8 @@ } if (status != OCI_SUCCESS) { OCIHandleFree_log_stat(dschp, OCI_HTYPE_DESCRIBE, status); + if (tablename != new_tablename) + free(tablename); return oci_error(sth, errhp, status, "OCIDescribeAny/OCIAttrGet/LOB refetch"); } if (DBIS->debug >= 3) @@ -1627,35 +1632,47 @@ break; OCIAttrGet_log_stat(colhd, OCI_DTYPE_PARAM, &col_dbtype, 0, OCI_ATTR_DATA_TYPE, errhp, status); - if (status) - break; + if (status) { + OCIDescriptorFree(colhd, OCI_DTYPE_PARAM); + break; + } OCIAttrGet_log_stat(colhd, OCI_DTYPE_PARAM, &col_name, &col_name_len, OCI_ATTR_NAME, errhp, status); - if (status) - break; + if (status) { + OCIDescriptorFree(colhd, OCI_DTYPE_PARAM); + break; + } if (DBIS->debug >= 3) PerlIO_printf(DBILOGFP, " lob refetch table col %d: '%.*s' otype %d\n", (int)i, (int)col_name_len,col_name, col_dbtype); - if (col_dbtype != SQLT_CLOB && col_dbtype != SQLT_BLOB) + if (col_dbtype != SQLT_CLOB && col_dbtype != SQLT_BLOB) { + OCIDescriptorFree(colhd, OCI_DTYPE_PARAM); continue; + } if (!lob_cols_hv) lob_cols_hv = newHV(); sv = newSViv(col_dbtype); - (void)sv_setpvn(sv, col_name, col_name_len); +/* (void)sv_setpvn(sv, col_name, col_name_len); #ifdef UTF8_SUPPORT DBD_SET_UTF8(sv); #endif - (void)SvIOK_on(sv); /* what a wonderful hack! */ + (void)SvIOK_on(sv);*/ /* what a wonderful hack! */ hv_store(lob_cols_hv, col_name,col_name_len, sv,0); + OCIDescriptorFree(colhd, OCI_DTYPE_PARAM); } + OCIHandleFree(dschp, OCI_HTYPE_DESCRIBE); if (status != OCI_SUCCESS) { - OCIHandleFree_log_stat(dschp, OCI_HTYPE_DESCRIBE, status); + if (tablename != new_tablename) + free(tablename); return oci_error(sth, errhp, status, "OCIDescribeAny/OCIParamGet/OCIAttrGet/LOB refetch"); } - if (!lob_cols_hv) + if (!lob_cols_hv) { + if (tablename != new_tablename) + free(tablename); return oci_error(sth, errhp, OCI_ERROR, "LOB refetch failed, no lobs in table"); + } /* our bind params are in %imp_sth->all_params_hv our table cols are in %lob_cols_hv @@ -1694,8 +1711,9 @@ else { /* got a type match - check it's safe */ SV *sv_other; char *p_other; + I32 i_other; /* would any other lob field match this type? */ - while( (sv_other = hv_iternextsv(lob_cols_hv, &p_other, &i)) != NULL ) { + while( (sv_other = hv_iternextsv(lob_cols_hv, &p_other, &i_other)) != NULL ) { if (phs->ftype != SvIV(sv_other)) continue; if (DBIS->debug >= 3) @@ -1703,6 +1721,10 @@ " both %s and %s have type %d - ambiguous\n", neatsvpv(sv,0), neatsvpv(sv_other,0), (int)SvIV(sv_other)); Safefree(lr); + sv_free((SV*)lob_cols_hv); + sv_free(sql_select); + if (tablename != new_tablename) + free(tablename); return oci_error(sth, errhp, OCI_ERROR, "Need bind_param(..., { ora_field=>... }) attribute to identify table LOB field names"); } @@ -1716,7 +1738,7 @@ " lob refetch %s param: otype %d, matched field '%s' %s(%s)\n", phs->name, phs->ftype, p, (phs->ora_field) ? "by name " : "by type ", sql_field); - hv_delete(lob_cols_hv, p, i, 0); + hv_delete(lob_cols_hv, p, i, G_DISCARD); fbh = &lr->fbh_ary[lr->num_fields++]; fbh->name = phs->name; fbh->ftype = phs->ftype; @@ -1734,8 +1756,12 @@ phs->name, phs->ftype); } } + sv_free((SV*)lob_cols_hv); if (unmatched_params) { Safefree(lr); + sv_free(sql_select); + if (tablename != new_tablename) + free(tablename); return oci_error(sth, errhp, OCI_ERROR, "Can't match some parameters to LOB fields in the table, check type and name"); } @@ -1746,6 +1772,8 @@ if (DBIS->debug >= 3) PerlIO_printf(DBILOGFP, " lob refetch sql: %s\n", SvPVX(sql_select)); + if (tablename != new_tablename) + free(tablename); lr->sql_select = sql_select; lr->stmthp = NULL; @@ -1759,15 +1787,24 @@ OCIStmtPrepare_log_stat(lr->stmthp, errhp, (text*)SvPVX(sql_select), SvCUR(sql_select), OCI_NTV_SYNTAX, OCI_DEFAULT, status); - if (status != OCI_SUCCESS) + if (status != OCI_SUCCESS) { + OCIHandleFree(lr->stmthp, OCI_HTYPE_STMT); + sv_free(lr->sql_select); + Safefree(lr); return oci_error(sth, errhp, status, "OCIStmtPrepare/LOB refetch"); + } /* bind the rowid input */ OCIDescriptorAlloc_ok(imp_sth->envhp, &lr->rowid, OCI_DTYPE_ROWID); OCIBindByName_log_stat(lr->stmthp, &lr->bindhp, errhp, (text*)":rid", 4, &lr->rowid, sizeof(OCIRowid*), SQLT_RDD, 0,0,0,0,0, OCI_DEFAULT, status); - if (status != OCI_SUCCESS) + if (status != OCI_SUCCESS) { + OCIDescriptorFree(lr->rowid, OCI_DTYPE_ROWID); + OCIHandleFree(lr->stmthp, OCI_HTYPE_STMT); + sv_free(lr->sql_select); + Safefree(lr); return oci_error(sth, errhp, status, "OCIBindByPos/LOB refetch"); + } /* define the output fields */ for(i=0; i < lr->num_fields; ++i) { @@ -1788,8 +1825,15 @@ OCIDefineByPos_log_stat(lr->stmthp, &defnp, errhp, (ub4)i+1, &fbh->desc_h, -1, (ub2)fbh->ftype, fbh->fb_ary->aindp, 0, fbh->fb_ary->arcode, OCI_DEFAULT, status); - if (status != OCI_SUCCESS) + if (status != OCI_SUCCESS) { + OCIDescriptorFree(lr->rowid, OCI_DTYPE_ROWID); + OCIHandleFree(lr->stmthp, OCI_HTYPE_STMT); + sv_free(lr->sql_select); + Safefree(lr); + fb_ary_free(fbh->fb_ary); + fbh->fb_ary = NULL; return oci_error(sth, errhp, status, "OCIDefineByPos/LOB refetch"); + } } imp_sth->lob_refetch = lr; /* structure copy */ @@ -1884,6 +1928,8 @@ } sv_free(lr->sql_select); sv_free(lr->fbh_ary_sv); + if (lr->rowid) + OCIDescriptorFree(lr->rowid, OCI_DTYPE_ROWID); Safefree(imp_sth->lob_refetch); imp_sth->lob_refetch = NULL; }
I'm applying it (in modified form) for DBD::Oracle 1.16. Please retest when it's released. Thanks!


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

Please report any issues with rt.cpan.org to rt-cpan-admin@bestpractical.com.