--- DBD-mysql-4.001/dbdimp.c Mon Jan 8 09:39:05 2007 +++ DBD-mysql-4.001/dbdimp.c Mon Jan 8 09:39:05 2007 @@ -240,7 +240,7 @@ if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, "\t-> mysql_to_perl_type\n"); if (dbis->debug >= 2) - PerlIO_printf(DBILOGFP, "\t->type %d\n"); + PerlIO_printf(DBILOGFP, "\t\t->type %d\n", type); switch (type) { case MYSQL_TYPE_DOUBLE: @@ -253,9 +253,6 @@ case MYSQL_TYPE_LONG: case MYSQL_TYPE_INT24: case MYSQL_TYPE_YEAR: -#if MYSQL_VERSION_ID > NEW_DATATYPE_VERSION - case MYSQL_TYPE_BIT: -#endif enum_type= MYSQL_TYPE_LONG; break; @@ -263,9 +260,6 @@ case MYSQL_TYPE_NEWDECIMAL: #endif case MYSQL_TYPE_DECIMAL: - enum_type= MYSQL_TYPE_DECIMAL; - break; - case MYSQL_TYPE_LONGLONG: /* No longlong in perl */ case MYSQL_TYPE_DATE: case MYSQL_TYPE_TIME: @@ -283,11 +277,22 @@ #if MYSQL_VERSION_ID > GEO_DATATYPE_VERSION case MYSQL_TYPE_GEOMETRY: #endif +#if MYSQL_VERSION_ID > NEW_DATATYPE_VERSION + case MYSQL_TYPE_BIT: /* Same as longlong, but in binary format */ +#endif case MYSQL_TYPE_BLOB: case MYSQL_TYPE_TINY_BLOB: enum_type= MYSQL_TYPE_BLOB; break; + case MYSQL_TYPE_MEDIUM_BLOB: + enum_type= MYSQL_TYPE_MEDIUM_BLOB; + break; + + case MYSQL_TYPE_LONG_BLOB: + enum_type= MYSQL_TYPE_LONG_BLOB; + break; + default: enum_type= MYSQL_TYPE_STRING; /* MySQL can handle all types as strings */ } @@ -438,11 +443,10 @@ bool bind_type_guessing) { - int rc; char *salloc, *statement_ptr; - char *statement_ptr_end, testchar, *ptr, *valbuf; + char *statement_ptr_end, *ptr, *valbuf; char *cp, *end; - int alen, i, j; + int alen, i; int slen= *slen_ptr; int limit_flag= 0; STRLEN vallen; @@ -576,7 +580,6 @@ else { int is_num = FALSE; - int c; valbuf= SvPV(ph->value, vallen); if (valbuf) @@ -1670,7 +1673,7 @@ } } if (dbis->debug >= 2) - PerlIO_printf(DBILOGFP, "imp_dbh->mysql_dr_connect: client_flags = %d\n", + PerlIO_printf(DBILOGFP, "imp_dbh->mysql_dr_connect: client_flags = %u\n", client_flag); #if MYSQL_VERSION_ID >= MULTIPLE_RESULT_SET_VERSION @@ -2316,7 +2319,7 @@ sv_2mortal(newSVpv(serverinfo, strlen(serverinfo))) : &sv_undef; } else if (strEQ(key, "sock")) - result= sv_2mortal(newSViv((IV) &imp_dbh->mysql)); + result= sv_2mortal(newSViv((IV)(long) &imp_dbh->mysql)); else if (strEQ(key, "sockfd")) result= sv_2mortal(newSViv((IV) imp_dbh->mysql.net.fd)); else if (strEQ(key, "stat")) @@ -2376,8 +2379,12 @@ int i; SV **svp; #if MYSQL_VERSION_ID >= SERVER_PREPARE_VERSION +#if MYSQL_VERSION_ID < LIMIT_PLACEHOLDER_VERSION + int limit_flag= 0; +#endif char *str_ptr; - int col_type, prepare_retval, limit_flag=0; + enum enum_field_types col_type; + int prepare_retval; MYSQL_BIND *bind, *bind_end; imp_sth_phb_t *fbind; #endif @@ -2426,15 +2433,24 @@ PerlIO_printf(DBILOGFP, "\t\tuse_server_side_prepare set, check LIMIT\n"); /* - This code is here because mysql < 5.1 didn't support placeholders - in prepared statements and also we have to disable some statements - for PS mode + This code is here because mysql < 5.0.7 didn't support + placeholders for LIMIT in prepared statements and + also we have to disable some statements for PS mode */ +#if MYSQL_VERSION_ID < LIMIT_PLACEHOLDER_VERSION if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, "\t\tneed to test for LIMIT\n"); +#endif for (str_ptr= statement; *str_ptr; str_ptr++) { +#if 0 + /* + There's a lot of cases that multi-result-set isn't necessary, + so disable PS mode by usage in Perl codes such as: + $sth = $dbh->prepare('CALL proc_multi_sets(?, ?)', + { mysql_server_prepare => 0 }); + */ /* Processing of multi-result-set is not possible due to lack of some calls in PS API. CALL() statement is disabled for PS @@ -2451,6 +2467,7 @@ PerlIO_printf(DBILOGFP, "Disable PS mode for CALL()\n"); imp_sth->use_server_side_prepare= 0; } +#endif #if MYSQL_VERSION_ID < LIMIT_PLACEHOLDER_VERSION /* @@ -2505,7 +2522,7 @@ if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, "\t\tERROR: Unable to return MYSQL_STMT structure \ - from mysql_stmt_init(): ERROR NO: %d ERROR MSG:%s\n", + from mysql_stmt_init(): ERROR NO: %u ERROR MSG:%s\n", mysql_errno(&imp_dbh->mysql), mysql_error(&imp_dbh->mysql)); } @@ -2522,7 +2539,7 @@ { if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, - "\t\tmysql_stmt_prepare %d %s\n", + "\t\tmysql_stmt_prepare %u %s\n", mysql_stmt_errno(imp_sth->stmt), mysql_stmt_error(imp_sth->stmt)); @@ -2553,7 +2570,6 @@ if (DBIc_NUM_PARAMS(imp_sth) > 0) { - int has_statement_fields= imp_sth->stmt->fields != 0; /* Allocate memory for bind variables */ imp_sth->bind= alloc_bind(DBIc_NUM_PARAMS(imp_sth)); imp_sth->fbind= alloc_fbind(DBIc_NUM_PARAMS(imp_sth)); @@ -2568,22 +2584,18 @@ bind++, fbind++, i++ ) { /* - if this statement has a result set, field types will be - correctly identified. If there is no result set, such as - with an INSERT, fields will not be defined, and all buffer_type - will default to MYSQL_TYPE_VAR_STRING + all buffer_type will default to MYSQL_TYPE_VAR_STRING */ - col_type= (has_statement_fields ? - imp_sth->stmt->fields[i].type : MYSQL_TYPE_STRING); + col_type= MYSQL_TYPE_STRING; bind->buffer_type= mysql_to_perl_type(col_type); if (dbis->debug >= 2) - PerlIO_printf(DBILOGFP, "\t\tmysql_to_perl_type returned %d\n", col_type); + PerlIO_printf(DBILOGFP, "\t\tmysql_to_perl_type returned %d\n", bind->buffer_type); bind->buffer= NULL; bind->length= &(fbind->length); - bind->is_null= (char*) &(fbind->is_null); + bind->is_null= &(fbind->is_null); fbind->is_null= 1; fbind->length= 0; } @@ -2797,7 +2809,7 @@ PerlIO_printf(DBILOGFP, " imp_sth->fields_count=%08lx\n", mysql_field_count(svsock)); - PerlIO_printf(DBILOGFP, " mysql_num_fields=%llu\n", + PerlIO_printf(DBILOGFP, " mysql_num_fields=%u\n", mysql_num_fields(imp_sth->result)); PerlIO_printf(DBILOGFP, " <- mysql_num_rows=%llu\n", @@ -3096,7 +3108,7 @@ } if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, - "\t<- mysql_internal_execute_41 returning %d rows\n", + "\t<- mysql_internal_execute_41 returning %llu rows\n", rows); return(rows); @@ -3108,7 +3120,7 @@ } if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, - " errno %d err message %s\n", + " errno %u err message %s\n", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); do_error(sth, mysql_stmt_errno(stmt), mysql_stmt_error(stmt), @@ -3272,7 +3284,7 @@ if (imp_sth->use_server_side_prepare) { int i; - int col_type; + enum enum_field_types col_type; int num_fields= DBIc_NUM_FIELDS(imp_sth); imp_sth_fbh_t *fbh; MYSQL_BIND *buffer; @@ -3317,10 +3329,10 @@ if (dbis->debug >= 2) { - PerlIO_printf(DBILOGFP,"\t\ti %d col_type %d fbh->length %d\n", + PerlIO_printf(DBILOGFP,"\t\ti %d col_type %d fbh->length %lu\n", i, col_type, fbh->length); PerlIO_printf(DBILOGFP, - "\t\tfields[i].length %d fields[i].type %d fields[i].charsetnr %d\n", + "\t\tfields[i].length %lu fields[i].type %d fields[i].charsetnr %u\n", fields[i].length, fields[i].type, fields[i].charsetnr); } @@ -3329,27 +3341,26 @@ buffer->buffer_type= mysql_to_perl_type(col_type); if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, "\t\tmysql_to_perl_type returned %d\n", - col_type); + buffer->buffer_type); buffer->buffer_length= fields[i].length; buffer->length= &(fbh->length); buffer->is_null= &(fbh->is_null); - Newz(908, fbh->data, fields[i].length, char); switch (buffer->buffer_type) { case MYSQL_TYPE_DOUBLE: - buffer->buffer= (char*) &fbh->ddata; + buffer->buffer= (char*) &fbh->u.ddata; break; case MYSQL_TYPE_LONG: - buffer->buffer= (char*) &fbh->ldata; + buffer->buffer= (char*) &fbh->u.ldata; buffer->is_unsigned= (fields[i].flags & UNSIGNED_FLAG) ? 1 : 0; break; case MYSQL_TYPE_STRING: - buffer->buffer= (char *) fbh->data; - default: - buffer->buffer= (char *) fbh->data; + Newz(908, fbh->u.data, fields[i].length, char); + fbh->is_alloc= TRUE; + buffer->buffer= fbh->u.data; } } @@ -3388,7 +3399,8 @@ AV* dbd_st_fetch(SV *sth, imp_sth_t* imp_sth) { - int num_fields, ChopBlanks, i, rc; + unsigned num_fields; + int ChopBlanks, i, rc; unsigned long *lengths; AV *av; int av_length, av_readonly; @@ -3490,7 +3502,7 @@ num_fields=mysql_stmt_field_count(imp_sth->stmt); if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, - "\t\tdbd_st_fetch called mysql_fetch, rc %d num_fields %d\n", + "\t\tdbd_st_fetch called mysql_fetch, rc %d num_fields %u\n", rc, num_fields); for ( @@ -3521,9 +3533,9 @@ if (dbis->debug > 2) PerlIO_printf(DBILOGFP,"\t\tRefetch BLOB/TEXT column: %d\n", i); - Renew(fbh->data, fbh->length, char); + Renew(fbh->u.data, fbh->length, char); buffer->buffer_length= fbh->length; - buffer->buffer= (char *) fbh->data; + buffer->buffer= fbh->u.data; /*TODO: Use offset instead of 0 to fetch only remain part of data*/ if (mysql_stmt_fetch_column(imp_sth->stmt, buffer , i, 0)) do_error(sth, mysql_stmt_errno(imp_sth->stmt), @@ -3536,24 +3548,27 @@ switch (buffer->buffer_type) { case MYSQL_TYPE_DOUBLE: if (dbis->debug > 2) - PerlIO_printf(DBILOGFP, "\t\tst_fetch double data %f\n", fbh->ddata); - sv_setnv(sv, fbh->ddata); + PerlIO_printf(DBILOGFP, "\t\tst_fetch double data %f\n", fbh->u.ddata); + sv_setnv(sv, fbh->u.ddata); break; case MYSQL_TYPE_LONG: if (dbis->debug > 2) - PerlIO_printf(DBILOGFP, "\t\tst_fetch int data %d, unsigned? %d\n", - fbh->ldata, buffer->is_unsigned); + PerlIO_printf(DBILOGFP, + buffer->is_unsigned + ? "\t\tst_fetch unsigned int data %lu\n" + : "\t\tst_fetch signed int data %li\n", + fbh->u.ldata); if (buffer->is_unsigned) - sv_setuv(sv, fbh->ldata); + sv_setuv(sv, fbh->u.ldata); else - sv_setiv(sv, fbh->ldata); + sv_setiv(sv, fbh->u.ldata); break; case MYSQL_TYPE_STRING: if (dbis->debug > 2) - PerlIO_printf(DBILOGFP, "\t\tst_fetch string data %s\n", fbh->data); - sv_setpvn(sv, fbh->data, fbh->length); + PerlIO_printf(DBILOGFP, "\t\tst_fetch string data %s\n", fbh->u.data); + sv_setpvn(sv, fbh->u.data, fbh->length); #ifdef sv_utf8_decode if(imp_dbh->enable_utf8) sv_utf8_decode(sv); @@ -3560,11 +3575,19 @@ #endif break; + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + if (dbis->debug > 2) + PerlIO_printf(DBILOGFP, "\t\tst_fetch binary data %lu bytes @%p\n", + fbh->length, fbh->u.data); + sv_setpvn(sv, fbh->u.data, fbh->length); + break; + default: if (dbis->debug > 2) PerlIO_printf(DBILOGFP, "\t\tERROR IN st_fetch_string"); - sv_setpvn(sv, fbh->data, fbh->length); - break; + sv_setpvn(sv, fbh->u.data, fbh->length); } } @@ -3571,7 +3594,7 @@ } if (dbis->debug >= 2) - PerlIO_printf(DBILOGFP, "\t<- dbd_st_fetch, %d cols\n", num_fields); + PerlIO_printf(DBILOGFP, "\t<- dbd_st_fetch, %u cols\n", num_fields); return av; } @@ -3585,7 +3608,7 @@ { PerlIO_printf(DBILOGFP, "\tdbd_st_fetch result set details\n"); PerlIO_printf(DBILOGFP, "\timp_sth->result=%08lx\n",imp_sth->result); - PerlIO_printf(DBILOGFP, "\tmysql_num_fields=%llu\n", + PerlIO_printf(DBILOGFP, "\tmysql_num_fields=%u\n", mysql_num_fields(imp_sth->result)); PerlIO_printf(DBILOGFP, "\tmysql_num_rows=%llu\n", mysql_num_rows(imp_sth->result)); @@ -3629,7 +3652,7 @@ if (av_length != num_fields) /* Resize array if necessary */ { if (dbis->debug >= 2) - PerlIO_printf(DBILOGFP, "\t<- dbd_st_fetch, size of results array(%d) != num_fields(%d)\n", + PerlIO_printf(DBILOGFP, "\t<- dbd_st_fetch, size of results array(%d) != num_fields(%u)\n", av_length, num_fields); if (dbis->debug >= 2) @@ -3684,7 +3707,7 @@ } if (dbis->debug >= 2) - PerlIO_printf(DBILOGFP, "\t<- dbd_st_fetch, %d cols\n", num_fields); + PerlIO_printf(DBILOGFP, "\t<- dbd_st_fetch, %u cols\n", num_fields); return av; #if MYSQL_VERSION_ID >= SERVER_PREPARE_VERSION @@ -3742,7 +3765,7 @@ if (imp_sth->use_server_side_prepare) { - if (imp_sth && imp_sth->stmt) + if (imp_sth->stmt) { if (!mysql_st_clean_cursor(sth, imp_sth)) { @@ -3750,19 +3773,11 @@ "Error happened while tried to clean up stmt",NULL); return 0; } + /* to avoid SIGSEGV when reusing this statement handle */ + imp_sth->stmt->bind_result_done= 0; } + /* clean up other statement allocations */ - if (DBIc_NUM_PARAMS(imp_sth) > 0) - { - if (dbis->debug >= 2) - PerlIO_printf(DBILOGFP, - "\tFreeing %d parameters\n", - DBIc_NUM_PARAMS(imp_sth)); - free_bind(imp_sth->bind); - free_fbind(imp_sth->fbind); - imp_sth->bind= NULL; - imp_sth->fbind= NULL; - } num_fields= DBIc_NUM_FIELDS(imp_sth); if (imp_sth->fbh) @@ -3769,11 +3784,11 @@ { for (fbh= imp_sth->fbh, i= 0; i < num_fields; i++, fbh++) { - if (fbh->data) - Safefree(fbh->data); + if (fbh->is_alloc) + Safefree(fbh->u.data); } - free_fbuffer(imp_sth->fbh); free_bind(imp_sth->buffer); + free_fbuffer(imp_sth->fbh); imp_sth->buffer= NULL; imp_sth->fbh= NULL; } @@ -3823,6 +3838,38 @@ int i; +#if MYSQL_VERSION_ID >= SERVER_PREPARE_VERSION + if (imp_sth->use_server_side_prepare) + { + if (imp_sth->stmt) + { + if (dbis->debug >= 2) + PerlIO_printf(DBILOGFP, + "\tdbd_st_destroy/server_side_prepare and stmt\n"); + if (mysql_stmt_close(imp_sth->stmt)) + { + PerlIO_printf(DBILOGFP, + "DESTROY: Error %s while close stmt\n", + (char *) mysql_stmt_error(imp_sth->stmt)); + do_error(sth, mysql_stmt_errno(imp_sth->stmt), + mysql_stmt_error(imp_sth->stmt), + mysql_stmt_sqlstate(imp_sth->stmt)); + } + if (DBIc_NUM_PARAMS(imp_sth) > 0) + { + if (dbis->debug >= 2) + PerlIO_printf(DBILOGFP, + "\tFreeing %d parameters\n", + DBIc_NUM_PARAMS(imp_sth)); + free_bind(imp_sth->bind); + free_fbind(imp_sth->fbind); + imp_sth->bind= NULL; + imp_sth->fbind= NULL; + } + } + } +#endif + /* dbd_st_finish has already been called by .xs code if needed. */ /* Free values allocated by dbd_bind_ph */ @@ -4106,12 +4153,11 @@ if (DBIc_NUM_PARAMS(imp_sth)) { unsigned int n; - SV *sv; char key[100]; I32 keylen; for (n= 0; n < DBIc_NUM_PARAMS(imp_sth); n++) { - keylen= sprintf(key, "%d", n); + keylen= sprintf(key, "%u", n); hv_store(pvhv, key, keylen, newSVsv(imp_sth->params[n].value), 0); } @@ -4145,7 +4191,7 @@ else if (strEQ(key, "mysql_length")) retsv= ST_FETCH_AV(AV_ATTRIB_LENGTH); else if (strEQ(key, "mysql_result")) - retsv= sv_2mortal(newSViv((IV) imp_sth->result)); + retsv= sv_2mortal(newSViv((IV)(long) imp_sth->result)); break; case 13: if (strEQ(key, "mysql_is_blob")) @@ -4156,7 +4202,7 @@ { /* We cannot return an IV, because the insertid is a long. */ if (dbis->debug >= 2) - PerlIO_printf(DBILOGFP, "INSERT ID %d\n", imp_sth->insertid); + PerlIO_printf(DBILOGFP, "INSERT ID %llu\n", imp_sth->insertid); return sv_2mortal(my_ulonglong2str(imp_sth->insertid)); } @@ -4256,10 +4302,10 @@ #if MYSQL_VERSION_ID >= SERVER_PREPARE_VERSION STRLEN slen; - char *buffer; - int buffer_is_null= 0; - int buffer_length= slen; - int buffer_type= 0; + char *buffer= NULL; + my_bool buffer_is_null; + unsigned long buffer_length= 0; + enum enum_field_types buffer_type; #endif if (param_num <= 0 || param_num > DBIc_NUM_PARAMS(imp_sth)) @@ -4285,7 +4331,9 @@ sql_type == SQL_SMALLINT || sql_type == SQL_FLOAT || sql_type == SQL_REAL || - sql_type == SQL_DOUBLE) ) + sql_type == SQL_DOUBLE || + sql_type == SQL_BIGINT || + sql_type == SQL_TINYINT) ) { if (! looks_like_number(value)) { @@ -4318,37 +4366,37 @@ #if MYSQL_VERSION_ID >= SERVER_PREPARE_VERSION if (imp_sth->use_server_side_prepare) { - if (SvOK(imp_sth->params[idx].value) && imp_sth->params[idx].value) - { - buffer_is_null= 0; + buffer_is_null= !(SvOK(imp_sth->params[idx].value) && imp_sth->params[idx].value); - switch(sql_type) { - case SQL_NUMERIC: - case SQL_INTEGER: - case SQL_SMALLINT: - case SQL_BIGINT: - case SQL_TINYINT: + switch(sql_type) { + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + buffer_type= MYSQL_TYPE_LONG; + if (!buffer_is_null) + { /* INT */ if (!SvIOK(imp_sth->params[idx].value) && dbis->debug >= 2) PerlIO_printf(DBILOGFP, "\t\tTRY TO BIND AN INT NUMBER\n"); - buffer_type= MYSQL_TYPE_LONG; imp_sth->fbind[idx].numeric_val.lval= SvIV(imp_sth->params[idx].value); - buffer=(void*)&(imp_sth->fbind[idx].numeric_val.lval); + buffer=(char*)&(imp_sth->fbind[idx].numeric_val.lval); if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, " SCALAR type %d ->%ld<- IS A INT NUMBER\n", - sql_type, (long) (*buffer)); - break; + (int)sql_type, *(long *)buffer); + } + break; - case SQL_DOUBLE: - case SQL_DECIMAL: - case SQL_FLOAT: - case SQL_REAL: + case SQL_FLOAT: + case SQL_REAL: + case SQL_DOUBLE: + buffer_type= MYSQL_TYPE_DOUBLE; + if (!buffer_is_null) + { if (!SvNOK(imp_sth->params[idx].value) && dbis->debug >= 2) PerlIO_printf(DBILOGFP, "\t\tTRY TO BIND A FLOAT NUMBER\n"); - buffer_type= MYSQL_TYPE_DOUBLE; imp_sth->fbind[idx].numeric_val.dval= SvNV(imp_sth->params[idx].value); buffer=(char*)&(imp_sth->fbind[idx].numeric_val.dval); @@ -4355,55 +4403,62 @@ if (dbis->debug >= 2) PerlIO_printf(DBILOGFP, " SCALAR type %d ->%f<- IS A FLOAT NUMBER\n", - sql_type, (double)(*buffer)); - break; + (int)sql_type, *(double *)buffer); + } + break; - case SQL_CHAR: - case SQL_VARCHAR: - case SQL_DATE: - case SQL_TIME: - case SQL_TIMESTAMP: - case SQL_LONGVARCHAR: - case SQL_BINARY: - case SQL_VARBINARY: - case SQL_LONGVARBINARY: - buffer_type= MYSQL_TYPE_BLOB; - break; + case SQL_BLOB: + case SQL_BINARY: + case SQL_VARBINARY: + case SQL_LONGVARBINARY: + case SQL_BIT: + buffer_type= MYSQL_TYPE_BLOB; + break; - default: - buffer_type= MYSQL_TYPE_STRING; - break; - } + case SQL_CHAR: + /* NUMERIC and DECIMAL can't be represented precisely by either long or double */ + case SQL_NUMERIC: + case SQL_DECIMAL: + case SQL_DATE: + case SQL_TIME: + case SQL_TIMESTAMP: + case SQL_VARCHAR: + case SQL_LONGVARCHAR: + /* BIGINT could overflow on long unless LP64 */ + case SQL_BIGINT: + default: + buffer_type= MYSQL_TYPE_STRING; + } - if (buffer_type == MYSQL_TYPE_STRING) + if (!buffer_is_null && !buffer) + { + buffer= SvPV(imp_sth->params[idx].value, slen); + buffer_length= slen; + if (dbis->debug >= 2) { - buffer= SvPV(imp_sth->params[idx].value, slen); - buffer_length= slen; - if (dbis->debug >= 2) + if (buffer_type == MYSQL_TYPE_BLOB) PerlIO_printf(DBILOGFP, + " SCALAR type %d ->%lu bytes @%p<- IS A BINARY\n", + (int)sql_type, buffer_length, buffer); + else + PerlIO_printf(DBILOGFP, " SCALAR type %d ->%s<- IS A STRING\n", - sql_type, buffer); + (int)sql_type, buffer); } } - else - { - buffer= NULL; - buffer_is_null= 1; - buffer_type= MYSQL_TYPE_NULL; - } /* Type of column was changed. Force to rebind */ if (imp_sth->bind[idx].buffer_type != buffer_type) - imp_sth->has_been_bound = 0; - - /* prepare has not been called */ - if (imp_sth->has_been_bound == 0) { + imp_sth->has_been_bound = 0; imp_sth->bind[idx].buffer_type= buffer_type; - imp_sth->bind[idx].buffer= buffer; - imp_sth->bind[idx].buffer_length= buffer_length; } - else /* prepare has been called */ + + /* Type change could occur at any idx, so always assign these. */ + imp_sth->bind[idx].buffer= buffer; + imp_sth->bind[idx].buffer_length= buffer_length; + /* prepare has been called */ + if (imp_sth->has_been_bound) { imp_sth->stmt->params[idx].buffer= buffer; imp_sth->stmt->params[idx].buffer_length= buffer_length; --- DBD-mysql-4.001/dbdimp.h Sun Jan 7 04:00:08 2007 +++ DBD-mysql-4.001/dbdimp.h Sun Jan 7 04:00:08 2007 @@ -31,7 +31,7 @@ #define SQL_STATE_VERSION 40101 #define MULTIPLE_RESULT_SET_VERSION 40102 #define SERVER_PREPARE_VERSION 40103 -#define LIMIT_PLACEHOLDER_VERSION 50100 +#define LIMIT_PLACEHOLDER_VERSION 50007 #define GEO_DATATYPE_VERSION 50007 #define NEW_DATATYPE_VERSION 50003 #define SSL_VERIFY_VERSION 50023 @@ -173,29 +173,32 @@ double dval; } numeric_val; unsigned long length; - char is_null; + my_bool is_null; } imp_sth_phb_t; /* * The dbd_describe uses this structure for storing * fields meta info. - * Added ddata, ldata, lldata for accomodate + * Added ddata, ldata for accomodate * being able to use different data types * 12.02.20004 PMG */ typedef struct imp_sth_fbh_st { unsigned long length; - bool is_null; - char *data; - int charsetnr; - double ddata; - long ldata; + my_bool is_null; + my_bool is_alloc:1; + union { + double ddata; + long ldata; + char *data; + } u; + unsigned charsetnr; } imp_sth_fbh_t; typedef struct imp_sth_fbind_st { unsigned long * length; - char * is_null; + my_bool * is_null; } imp_sth_fbind_t; @@ -321,3 +324,7 @@ extern int mysql_db_reconnect(SV*); int mysql_st_free_result_sets (SV * sth, imp_sth_t * imp_sth); + +int parse_number(char *, STRLEN, char **); +int dbd_st_more_results(SV*, imp_sth_t*); +extern int is_prefix(const char *, const char *); --- DBD-mysql-4.001/mysql.xs Mon Jan 8 09:39:05 2007 +++ DBD-mysql-4.001/mysql.xs Mon Jan 8 09:39:05 2007 @@ -265,17 +265,7 @@ MYSQL_RES* result= NULL; #if MYSQL_VERSION_ID >= SERVER_PREPARE_VERSION STRLEN slen; - char *str_ptr, *statement_ptr, *buffer; - int has_binded; - int col_type= MYSQL_TYPE_STRING; - int buffer_is_null= 0; - int buffer_length= slen; - int buffer_type= 0; - int param_type= SQL_VARCHAR; - int use_server_side_prepare= 0; - MYSQL_STMT *stmt= NULL; - MYSQL_BIND *bind= NULL; - imp_sth_phb_t *fbind= NULL; + int use_server_side_prepare= 0; /* * Globaly enabled using of server side prepared statement @@ -302,9 +292,9 @@ if (use_server_side_prepare) { - str_ptr= SvPV(statement, slen); + char *str_ptr= SvPV(statement, slen); - stmt= mysql_stmt_init(&imp_dbh->mysql); + MYSQL_STMT *stmt= mysql_stmt_init(&imp_dbh->mysql); if (mysql_stmt_prepare(stmt, str_ptr, strlen(str_ptr))) { @@ -329,6 +319,9 @@ } else { + int has_binded; + MYSQL_BIND *bind= NULL; + imp_sth_phb_t *fbind= NULL; /* * 'items' is the number of arguments passed to XSUB, supplied by xsubpp * compiler, as listed in manpage for perlxs @@ -348,7 +341,11 @@ for (i = 0; i < num_params; i++) { - int defined= 0; + enum enum_field_types col_type, buffer_type; + int param_type; + char *buffer= NULL; + my_bool buffer_is_null= 1; + unsigned long buffer_length= 0; params[i].value= ST(i+3); if (params[i].value) @@ -356,119 +353,143 @@ if (SvMAGICAL(params[i].value)) mg_get(params[i].value); if (SvOK(params[i].value)) - defined= 1; + buffer_is_null= 0; } - if (defined) - { - buffer= SvPV(params[i].value, slen); - buffer_is_null= 0; - buffer_length= slen; - } - else - { - buffer= NULL; - buffer_is_null= 1; - buffer_length= 0; - } /* - if this statement has a result set, field types will be correctly - identified. If there is no result set, such as with an INSERT, - fields will not be defined, and all buffer_type will default to - MYSQL_TYPE_VAR_STRING + all buffer_type will default to MYSQL_TYPE_VAR_STRING */ - col_type= (stmt->fields) ? stmt->fields[i].type : MYSQL_TYPE_STRING; + col_type= MYSQL_TYPE_STRING; switch (col_type) { -#if MYSQL_VERSION_ID > 50003 + case MYSQL_TYPE_DECIMAL: +#if MYSQL_VERSION_ID > NEW_DATATYPE_VERSION case MYSQL_TYPE_NEWDECIMAL: #endif - case MYSQL_TYPE_DECIMAL: param_type= SQL_DECIMAL; - buffer_type= MYSQL_TYPE_DOUBLE; break; - - case MYSQL_TYPE_DOUBLE: - param_type= SQL_DOUBLE; - buffer_type= MYSQL_TYPE_DOUBLE; + case MYSQL_TYPE_TINY: + param_type= SQL_TINYINT; break; - - case MYSQL_TYPE_FLOAT: - buffer_type= MYSQL_TYPE_DOUBLE; - param_type= SQL_FLOAT; - break; - case MYSQL_TYPE_SHORT: - buffer_type= MYSQL_TYPE_DOUBLE; - param_type= SQL_FLOAT; + case MYSQL_TYPE_YEAR: + param_type= SQL_SMALLINT; break; - - case MYSQL_TYPE_TINY: - buffer_type= MYSQL_TYPE_DOUBLE; + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + param_type= SQL_INTEGER; + break; + case MYSQL_TYPE_FLOAT: param_type= SQL_FLOAT; break; - - case MYSQL_TYPE_LONG: - buffer_type= MYSQL_TYPE_LONG; - param_type= SQL_BIGINT; + case MYSQL_TYPE_DOUBLE: + param_type= SQL_DOUBLE; break; - - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_YEAR: - buffer_type= MYSQL_TYPE_LONG; - param_type= SQL_INTEGER; + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + param_type= SQL_TIMESTAMP; break; - case MYSQL_TYPE_LONGLONG: - /* perl handles long long as double - * so we'll set this to string */ - buffer_type= MYSQL_TYPE_STRING; - param_type= SQL_VARCHAR; + param_type= SQL_BIGINT; break; - - case MYSQL_TYPE_NEWDATE: case MYSQL_TYPE_DATE: - buffer_type= MYSQL_TYPE_STRING; + case MYSQL_TYPE_NEWDATE: param_type= SQL_DATE; break; - case MYSQL_TYPE_TIME: - buffer_type= MYSQL_TYPE_STRING; param_type= SQL_TIME; break; - - case MYSQL_TYPE_TIMESTAMP: - buffer_type= MYSQL_TYPE_STRING; - param_type= SQL_TIMESTAMP; +#if MYSQL_VERSION_ID > NEW_DATATYPE_VERSION + case MYSQL_TYPE_BIT: + param_type= SQL_BIT; break; - +#endif + case MYSQL_TYPE_TINY_BLOB: + param_type= SQL_VARBINARY; + break; + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: +#if MYSQL_VERSION_ID > GEO_DATATYPE_VERSION + case MYSQL_TYPE_GEOMETRY: +#endif + param_type= SQL_LONGVARBINARY; + break; +#if MYSQL_VERSION_ID > NEW_DATATYPE_VERSION + case MYSQL_TYPE_VARCHAR: +#endif + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: - case MYSQL_TYPE_DATETIME: - buffer_type= MYSQL_TYPE_STRING; + default: param_type= SQL_VARCHAR; + } + + switch(param_type) { + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + buffer_type= MYSQL_TYPE_LONG; + if (!buffer_is_null) + { + /* INT */ + if (!SvIOK(params[i].value) && dbis->debug >= 2) + PerlIO_printf(DBILOGFP, "\t\tTRY TO BIND AN INT NUMBER\n"); + + fbind[i].numeric_val.lval= SvIV(params[i].value); + buffer=(char*)&(fbind[i].numeric_val.lval); + } break; - case MYSQL_TYPE_BLOB: - buffer_type= MYSQL_TYPE_BLOB; - param_type= SQL_BINARY; + case SQL_FLOAT: + case SQL_REAL: + case SQL_DOUBLE: + buffer_type= MYSQL_TYPE_DOUBLE; + if (!buffer_is_null) + { + if (!SvNOK(params[i].value) && dbis->debug >= 2) + PerlIO_printf(DBILOGFP, "\t\tTRY TO BIND A FLOAT NUMBER\n"); + + fbind[i].numeric_val.dval= SvNV(params[i].value); + buffer=(char*)&(fbind[i].numeric_val.dval); + } break; - case MYSQL_TYPE_GEOMETRY: + case SQL_BLOB: + case SQL_BINARY: + case SQL_VARBINARY: + case SQL_LONGVARBINARY: + case SQL_BIT: buffer_type= MYSQL_TYPE_BLOB; - param_type= SQL_BINARY; break; - + case SQL_CHAR: + case SQL_NUMERIC: + case SQL_DECIMAL: + case SQL_DATE: + case SQL_TIME: + case SQL_TIMESTAMP: + case SQL_VARCHAR: + case SQL_LONGVARCHAR: + /* perl handles long long as double + * so we'll set this to string */ + case SQL_BIGINT: default: buffer_type= MYSQL_TYPE_STRING; - param_type= SQL_VARCHAR; - break; } + if (!buffer_is_null && !buffer) + { + buffer= SvPV(params[i].value, slen); + buffer_length= slen; + } + bind[i].buffer_type = buffer_type; bind[i].buffer_length= buffer_length; bind[i].buffer= buffer; + bind[i].length= &(fbind[i].length); + bind[i].is_null= &(fbind[i].is_null); fbind[i].length= buffer_length; fbind[i].is_null= buffer_is_null; params[i].type= param_type; @@ -577,7 +598,6 @@ { #if (MYSQL_VERSION_ID >= MULTIPLE_RESULT_SET_VERSION) D_imp_sth(sth); - int retval; if (dbd_st_more_results(sth, imp_sth)) { RETVAL=1; --- DBD-mysql-4.001/t/80procs.t Sun Dec 24 22:35:46 2006 +++ DBD-mysql-4.001/t/80procs.t Sun Dec 24 22:35:46 2006 @@ -140,7 +140,8 @@ DbiError($dbh->err, $dbh->errstr); - Test($state or $sth = $dbh->prepare("call test_multi_sets()")) or + Test($state or $sth = $dbh->prepare("call test_multi_sets()", + { mysql_server_prepare => 0 })) or DbiError($dbh->err, $dbh->errstr); Test($state or $rows = $sth->execute()) or