| /* |
| /* |
| Copyright (c) 2012-2013, Oracle and/or its affiliates. All rights reserved. |
| Copyright (c) 2012-2013, Oracle and/or its affiliates. All rights reserved. |
| |
| |
| The MySQL Connector/ODBC is licensed under the terms of the GPLv2 |
| The MySQL Connector/ODBC is licensed under the terms of the GPLv2 |
| <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most |
| <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most |
| MySQL Connectors. There are special exceptions to the terms and |
| MySQL Connectors. There are special exceptions to the terms and |
| conditions of the GPLv2 as it is applied to this software, see the |
| conditions of the GPLv2 as it is applied to this software, see the |
| FLOSS License Exception |
| FLOSS License Exception |
| <http://www.mysql.com/about/legal/licensing/foss-exception.html>. |
| <http://www.mysql.com/about/legal/licensing/foss-exception.html>. |
| |
| |
| This program is free software; you can redistribute it and/or modify |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published |
| it under the terms of the GNU General Public License as published |
| by the Free Software Foundation; version 2 of the License. |
| by the Free Software Foundation; version 2 of the License. |
| |
| |
| This program is distributed in the hope that it will be useful, but |
| This program is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| for more details. |
| |
| |
| You should have received a copy of the GNU General Public License along |
| You should have received a copy of the GNU General Public License along |
| with this program; if not, write to the Free Software Foundation, Inc., |
| with this program; if not, write to the Free Software Foundation, Inc., |
| 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| */ |
| |
| |
| /** |
| /** |
| @file ssps.c |
| @file ssps.c |
| @brief Functions to support use of Server Side Prepared Statements. |
| @brief Functions to support use of Server Side Prepared Statements. |
| */ |
| */ |
| |
| |
| #include "driver.h" |
| #include "driver.h" |
| |
| |
| |
| |
| |
| |
| /* {{{ my_l_to_a() -I- */ |
| /* {{{ my_l_to_a() -I- */ |
| static char * my_l_to_a(char * buf, size_t buf_size, long long a) |
| static char * my_l_to_a(char * buf, size_t buf_size, long long a) |
| { |
| { |
| snprintf(buf, buf_size, "%lld", (long long) a); |
| snprintf(buf, buf_size, "%lld", (long long) a); |
| return buf; |
| return buf; |
| } |
| } |
| /* }}} */ |
| /* }}} */ |
| |
| |
| |
| |
| /* {{{ my_ul_to_a() -I- */ |
| /* {{{ my_ul_to_a() -I- */ |
| static char * my_ul_to_a(char * buf, size_t buf_size, unsigned long long a) |
| static char * my_ul_to_a(char * buf, size_t buf_size, unsigned long long a) |
| { |
| { |
| snprintf(buf, buf_size, "%llu", (unsigned long long) a); |
| snprintf(buf, buf_size, "%llu", (unsigned long long) a); |
| return buf; |
| return buf; |
| } |
| } |
| /* }}} */ |
| /* }}} */ |
| |
| |
| |
| |
| /* {{{ my_f_to_a() -I- */ |
| /* {{{ my_f_to_a() -I- */ |
| static char * my_f_to_a(char * buf, size_t buf_size, double a) |
| static char * my_f_to_a(char * buf, size_t buf_size, double a) |
| { |
| { |
| snprintf(buf, buf_size, "%f", a); |
| snprintf(buf, buf_size, "%f", a); |
| return buf; |
| return buf; |
| } |
| } |
| /* }}} */ |
| /* }}} */ |
| |
| |
| |
| |
| /* {{{ ssps_init() -I- */ |
| /* {{{ ssps_init() -I- */ |
| void ssps_init(STMT *stmt) |
| void ssps_init(STMT *stmt) |
| { |
| { |
| stmt->ssps= mysql_stmt_init(&stmt->dbc->mysql); |
| stmt->ssps= mysql_stmt_init(&stmt->dbc->mysql); |
| |
| |
| stmt->result_bind= 0; |
| stmt->result_bind= 0; |
| } |
| } |
| /* }}} */ |
| /* }}} */ |
| |
| |
| |
| |
| char * numeric2binary(char * dst, long long src, unsigned int byte_count) |
| char * numeric2binary(char * dst, long long src, unsigned int byte_count) |
| { |
| { |
| char byte; |
| char byte; |
| |
| |
| while (byte_count) |
| while (byte_count) |
| { |
| { |
| byte= src & 0xff; |
| byte= src & 0xff; |
| *(dst+(--byte_count))= byte; |
| *(dst+(--byte_count))= byte; |
| src= src >> 8; |
| src= src >> 8; |
| } |
| } |
| |
| |
| return dst; |
| return dst; |
| } |
| } |
| |
| |
| |
| |
| SQLRETURN SQL_API |
| SQLRETURN SQL_API |
| sql_get_data(STMT *stmt, SQLSMALLINT fCType, uint column_number, |
| sql_get_data(STMT *stmt, SQLSMALLINT fCType, uint column_number, |
| SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue, |
| SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue, |
| char *value, ulong length, DESCREC *arrec); |
| char *value, ulong length, DESCREC *arrec); |
| |
| |
| /** |
| /** |
| @returns TRUE if the resultset is SP OUT params |
| @returns TRUE if the resultset is SP OUT params |
| Basically it makes sense with prepared statements only |
| Basically it makes sense with prepared statements only |
| */ |
| */ |
| BOOL ssps_get_out_params(STMT *stmt) |
| BOOL ssps_get_out_params(STMT *stmt) |
| { |
| { |
| /* If we use prepared statement, and the query is CALL and we have any |
| /* If we use prepared statement, and the query is CALL and we have any |
| user's parameter described as INOUT or OUT and that is only result */ |
| user's parameter described as INOUT or OUT and that is only result */ |
| if (is_call_procedure(&stmt->query)) |
| if (is_call_procedure(&stmt->query)) |
| { |
| { |
| MYSQL_ROW values= NULL; |
| MYSQL_ROW values= NULL; |
| DESCREC *iprec, *aprec; |
| DESCREC *iprec, *aprec; |
| uint counter= 0; |
| uint counter= 0; |
| int i; |
| int i; |
| |
| |
| /*Since OUT parameters can be completely different - we have to free current |
| /*Since OUT parameters can be completely different - we have to free current |
| bind and bind new */ |
| bind and bind new */ |
| |
| |
| free_result_bind(stmt); |
| free_result_bind(stmt); |
| /* Thus function interface has to be changed */ |
| /* Thus function interface has to be changed */ |
| if (ssps_bind_result(stmt) == 0) |
| if (ssps_bind_result(stmt) == 0) |
| { |
| { |
| values= fetch_row(stmt); |
| values= fetch_row(stmt); |
| |
| |
| if (stmt->fix_fields) |
| if (stmt->fix_fields) |
| { |
| { |
| values= (*stmt->fix_fields)(stmt,values); |
| values= (*stmt->fix_fields)(stmt,values); |
| } |
| } |
| } |
| } |
| |
| |
| assert(values); |
| assert(values); |
| |
| |
| /* Then current result is out params */ |
| /* Then current result is out params */ |
| stmt->out_params_state= 2; |
| stmt->out_params_state= 2; |
| |
| |
| if (values != NULL && got_out_parameters(stmt)) |
| if (values != NULL && got_out_parameters(stmt)) |
| { |
| { |
| for (i= 0; i < myodbc_min(stmt->ipd->count, stmt->apd->count); ++i) |
| for (i= 0; i < myodbc_min(stmt->ipd->count, stmt->apd->count); ++i) |
| { |
| { |
| /* Making bit field look "normally" */ |
| |
| if (stmt->result_bind[counter].buffer_type == MYSQL_TYPE_BIT) |
| |
| { |
| |
| MYSQL_FIELD *field= mysql_fetch_field_direct(stmt->result, counter); |
| |
| unsigned long long numeric; |
| |
| |
| |
| assert(field->type == MYSQL_TYPE_BIT); |
| |
| /* terminating with NULL */ |
| |
| values[counter][*stmt->result_bind[counter].length]= '\0'; |
| |
| numeric= strtoull(values[counter], NULL, 10); |
| |
| |
| |
| *stmt->result_bind[counter].length= (field->length+7)/8; |
| |
| numeric2binary(values[counter], numeric, |
| |
| *stmt->result_bind[counter].length); |
| |
| |
| |
| } |
| |
| |
| |
| iprec= desc_get_rec(stmt->ipd, i, FALSE); |
| iprec= desc_get_rec(stmt->ipd, i, FALSE); |
| aprec= desc_get_rec(stmt->apd, i, FALSE); |
| aprec= desc_get_rec(stmt->apd, i, FALSE); |
| assert(iprec && aprec); |
| assert(iprec && aprec); |
| |
| |
| if ((iprec->parameter_type == SQL_PARAM_INPUT_OUTPUT |
| if ((iprec->parameter_type == SQL_PARAM_INPUT_OUTPUT |
| || iprec->parameter_type == SQL_PARAM_OUTPUT)) |
| || iprec->parameter_type == SQL_PARAM_OUTPUT)) |
| { |
| { |
| |
| /* Making bit field look "normally" */ |
| |
| if (stmt->result_bind[counter].buffer_type == MYSQL_TYPE_BIT) |
| |
| { |
| |
| MYSQL_FIELD *field= mysql_fetch_field_direct(stmt->result, counter); |
| |
| unsigned long long numeric; |
| |
| |
| |
| assert(field->type == MYSQL_TYPE_BIT); |
| |
| /* terminating with NULL */ |
| |
| values[counter][*stmt->result_bind[counter].length]= '\0'; |
| |
| numeric= strtoull(values[counter], NULL, 10); |
| |
| |
| |
| *stmt->result_bind[counter].length= (field->length+7)/8; |
| |
| numeric2binary(values[counter], numeric, |
| |
| *stmt->result_bind[counter].length); |
| |
| |
| |
| } |
| |
| |
| if (aprec->data_ptr) |
| if (aprec->data_ptr) |
| { |
| { |
| unsigned long length= *stmt->result_bind[counter].length; |
| unsigned long length= *stmt->result_bind[counter].length; |
| char *target= NULL; |
| char *target= NULL; |
| SQLLEN *octet_length_ptr= NULL; |
| SQLLEN *octet_length_ptr= NULL; |
| SQLLEN *indicator_ptr= NULL; |
| SQLLEN *indicator_ptr= NULL; |
| SQLINTEGER default_size; |
| SQLINTEGER default_size; |
| |
| |
| if (aprec->octet_length_ptr) |
| if (aprec->octet_length_ptr) |
| { |
| { |
| octet_length_ptr= ptr_offset_adjust(aprec->octet_length_ptr, |
| octet_length_ptr= ptr_offset_adjust(aprec->octet_length_ptr, |
| stmt->apd->bind_offset_ptr, |
| stmt->apd->bind_offset_ptr, |
| stmt->apd->bind_type, |
| stmt->apd->bind_type, |
| sizeof(SQLLEN), 0); |
| sizeof(SQLLEN), 0); |
| } |
| } |
| |
| |
| indicator_ptr= ptr_offset_adjust(aprec->indicator_ptr, |
| indicator_ptr= ptr_offset_adjust(aprec->indicator_ptr, |
| stmt->apd->bind_offset_ptr, |
| stmt->apd->bind_offset_ptr, |
| stmt->apd->bind_type, |
| stmt->apd->bind_type, |
| sizeof(SQLLEN), 0); |
| sizeof(SQLLEN), 0); |
| |
| |
| default_size= bind_length(aprec->concise_type, |
| default_size= bind_length(aprec->concise_type, |
| aprec->octet_length); |
| aprec->octet_length); |
| target= ptr_offset_adjust(aprec->data_ptr, stmt->apd->bind_offset_ptr, |
| target= ptr_offset_adjust(aprec->data_ptr, stmt->apd->bind_offset_ptr, |
| stmt->apd->bind_type, default_size, 0); |
| stmt->apd->bind_type, default_size, 0); |
| |
| |
| reset_getdata_position(stmt); |
| reset_getdata_position(stmt); |
| |
| |
| sql_get_data(stmt, aprec->concise_type, counter, |
| sql_get_data(stmt, aprec->concise_type, counter, |
| target, aprec->octet_length, indicator_ptr, |
| target, aprec->octet_length, indicator_ptr, |
| values[counter], length, aprec); |
| values[counter], length, aprec); |
| |
| |
| /* TODO: solve that globally */ |
| /* TODO: solve that globally */ |
| if (octet_length_ptr != NULL && indicator_ptr != NULL |
| if (octet_length_ptr != NULL && indicator_ptr != NULL |
| && octet_length_ptr != indicator_ptr |
| && octet_length_ptr != indicator_ptr |
| && *indicator_ptr != SQL_NULL_DATA) |
| && *indicator_ptr != SQL_NULL_DATA) |
| { |
| { |
| *octet_length_ptr= *indicator_ptr; |
| *octet_length_ptr= *indicator_ptr; |
| } |
| } |
| } |
| } |
| ++counter; |
| ++counter; |
| } |
| } |
| } |
| } |
| } |
| } |
| /* This MAGICAL fetch is required */ |
| /* This MAGICAL fetch is required */ |
| mysql_stmt_fetch(stmt->ssps); |
| mysql_stmt_fetch(stmt->ssps); |
| |
| |
| return TRUE; |
| return TRUE; |
| } |
| } |
| return FALSE; |
| return FALSE; |
| } |
| } |
| |
| |
| |
| |
| int ssps_get_result(STMT *stmt) |
| int ssps_get_result(STMT *stmt) |
| { |
| { |
| if (stmt->result) |
| if (stmt->result) |
| { |
| { |
| if (!if_forward_cache(stmt)) |
| if (!if_forward_cache(stmt)) |
| { |
| { |
| return mysql_stmt_store_result(stmt->ssps); |
| return mysql_stmt_store_result(stmt->ssps); |
| } |
| } |
| |
| |
| } |
| } |
| |
| |
| return 0; |
| return 0; |
| } |
| } |
| |
| |
| |
| |
| void free_result_bind(STMT *stmt) |
| void free_result_bind(STMT *stmt) |
| { |
| { |
| if (stmt->result_bind != NULL) |
| if (stmt->result_bind != NULL) |
| { |
| { |
| int i, field_cnt= field_count(stmt); |
| int i, field_cnt= field_count(stmt); |
| |
| |
| x_free(stmt->result_bind[0].is_null); |
| x_free(stmt->result_bind[0].is_null); |
| x_free(stmt->result_bind[0].length); |
| x_free(stmt->result_bind[0].length); |
| x_free(stmt->result_bind[0].error); |
| x_free(stmt->result_bind[0].error); |
| |
| |
| /* buffer was allocated for each column */ |
| /* buffer was allocated for each column */ |
| for (i= 0; i < field_cnt; i++) |
| for (i= 0; i < field_cnt; i++) |
| { |
| { |
| x_free(stmt->result_bind[i].buffer); |
| x_free(stmt->result_bind[i].buffer); |
| } |
| } |
| |
| |
| x_free(stmt->result_bind); |
| x_free(stmt->result_bind); |
| stmt->result_bind= 0; |
| stmt->result_bind= 0; |
| |
| |
| x_free(stmt->array); |
| x_free(stmt->array); |
| stmt->array= 0; |
| stmt->array= 0; |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| void ssps_close(STMT *stmt) |
| void ssps_close(STMT *stmt) |
| { |
| { |
| if (stmt->ssps != NULL) |
| if (stmt->ssps != NULL) |
| { |
| { |
| free_result_bind(stmt); |
| free_result_bind(stmt); |
| |
| |
| if (mysql_stmt_close(stmt->ssps) != '\0') |
| if (mysql_stmt_close(stmt->ssps) != '\0') |
| assert(!"Could not close stmt"); |
| assert(!"Could not close stmt"); |
| |
| |
| stmt->ssps= NULL; |
| stmt->ssps= NULL; |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| /* The structure and following allocation function are borrowed from c/c++ and adopted */ |
| /* The structure and following allocation function are borrowed from c/c++ and adopted */ |
| typedef struct tagBST |
| typedef struct tagBST |
| { char * buffer; |
| { char * buffer; |
| size_t size; |
| size_t size; |
| enum enum_field_types type; |
| enum enum_field_types type; |
| } st_buffer_size_type; |
| } st_buffer_size_type; |
| |
| |
| |
| |
| /* {{{ allocate_buffer_for_field() -I- */ |
| /* {{{ allocate_buffer_for_field() -I- */ |
| static st_buffer_size_type |
| static st_buffer_size_type |
| allocate_buffer_for_field(const MYSQL_FIELD * const field, BOOL outparams) |
| allocate_buffer_for_field(const MYSQL_FIELD * const field, BOOL outparams) |
| { |
| { |
| st_buffer_size_type result= {NULL, 0, field->type}; |
| st_buffer_size_type result= {NULL, 0, field->type}; |
| |
| |
| switch (field->type) { |
| switch (field->type) { |
| case MYSQL_TYPE_NULL: |
| case MYSQL_TYPE_NULL: |
| break; |
| break; |
| |
| |
| case MYSQL_TYPE_TINY: |
| case MYSQL_TYPE_TINY: |
| result.size= 1; |
| result.size= 1; |
| break; |
| break; |
| |
| |
| case MYSQL_TYPE_SHORT: |
| case MYSQL_TYPE_SHORT: |
| result.size=2; |
| result.size=2; |
| break; |
| break; |
| |
| |
| case MYSQL_TYPE_INT24: |
| case MYSQL_TYPE_INT24: |
| case MYSQL_TYPE_LONG: |
| case MYSQL_TYPE_LONG: |
| case MYSQL_TYPE_FLOAT: |
| case MYSQL_TYPE_FLOAT: |
| result.size=4; |
| result.size=4; |
| break; |
| break; |
| |
| |
| case MYSQL_TYPE_DOUBLE: |
| case MYSQL_TYPE_DOUBLE: |
| case MYSQL_TYPE_LONGLONG: |
| case MYSQL_TYPE_LONGLONG: |
| result.size=8; |
| result.size=8; |
| break; |
| break; |
| |
| |
| case MYSQL_TYPE_YEAR: |
| case MYSQL_TYPE_YEAR: |
| result.size=2; |
| result.size=2; |
| break; |
| break; |
| |
| |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_DATE: |
| case MYSQL_TYPE_DATE: |
| case MYSQL_TYPE_TIME: |
| case MYSQL_TYPE_TIME: |
| case MYSQL_TYPE_DATETIME: |
| case MYSQL_TYPE_DATETIME: |
| result.size=sizeof(MYSQL_TIME); |
| result.size=sizeof(MYSQL_TIME); |
| break; |
| break; |
| |
| |
| case MYSQL_TYPE_TINY_BLOB: |
| case MYSQL_TYPE_TINY_BLOB: |
| case MYSQL_TYPE_MEDIUM_BLOB: |
| case MYSQL_TYPE_MEDIUM_BLOB: |
| case MYSQL_TYPE_LONG_BLOB: |
| case MYSQL_TYPE_LONG_BLOB: |
| case MYSQL_TYPE_BLOB: |
| case MYSQL_TYPE_BLOB: |
| case MYSQL_TYPE_STRING: |
| case MYSQL_TYPE_STRING: |
| case MYSQL_TYPE_VAR_STRING: |
| case MYSQL_TYPE_VAR_STRING: |
| /* We will get length with fetch and then fetch column */ |
| /* We will get length with fetch and then fetch column */ |
| if (field->length > 0 && field->length < 1025) |
| if (field->length > 0 && field->length < 1025) |
| result.size= field->length + 1; |
| result.size= field->length + 1; |
| break; |
| break; |
| |
| |
| case MYSQL_TYPE_DECIMAL: |
| case MYSQL_TYPE_DECIMAL: |
| case MYSQL_TYPE_NEWDECIMAL: |
| case MYSQL_TYPE_NEWDECIMAL: |
| result.size=64; |
| result.size=64; |
| break; |
| break; |
| |
| |
| #if A1 |
| #if A1 |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_YEAR: |
| case MYSQL_TYPE_YEAR: |
| result.size= 10; |
| result.size= 10; |
| break; |
| break; |
| #endif |
| #endif |
| #if A0 |
| #if A0 |
| // There two are not sent over the wire |
| // There two are not sent over the wire |
| case MYSQL_TYPE_ENUM: |
| case MYSQL_TYPE_ENUM: |
| case MYSQL_TYPE_SET: |
| case MYSQL_TYPE_SET: |
| #endif |
| #endif |
| case MYSQL_TYPE_BIT: |
| case MYSQL_TYPE_BIT: |
| result.type= MYSQL_TYPE_BIT; |
| result.type= MYSQL_TYPE_BIT; |
| if (outparams) |
| if (outparams) |
| { |
| { |
| /* For out params we surprisingly get it as string representation of a |
| /* For out params we surprisingly get it as string representation of a |
| number representing those bits. Allocating buffer to accommodate |
| number representing those bits. Allocating buffer to accommodate |
| largest string possible - 8 byte number + NULL terminator. |
| largest string possible - 8 byte number + NULL terminator. |
| We will need to terminate the string to convert it to a number */ |
| We will need to terminate the string to convert it to a number */ |
| result.size= 30; |
| result.size= 30; |
| } |
| } |
| else |
| else |
| { |
| { |
| result.size= (field->length + 7)/8; |
| result.size= (field->length + 7)/8; |
| } |
| } |
| |
| |
| break; |
| break; |
| case MYSQL_TYPE_GEOMETRY: |
| case MYSQL_TYPE_GEOMETRY: |
| default: |
| default: |
| /* Error? */ |
| /* Error? */ |
| 1; |
| 1; |
| } |
| } |
| |
| |
| if (result.size > 0) |
| if (result.size > 0) |
| { |
| { |
| result.buffer=my_malloc(result.size, MYF(0)); |
| result.buffer=my_malloc(result.size, MYF(0)); |
| } |
| } |
| |
| |
| return result; |
| return result; |
| } |
| } |
| /* }}} */ |
| /* }}} */ |
| |
| |
| |
| |
| static MYSQL_ROW fetch_varlength_columns(STMT *stmt, MYSQL_ROW columns) |
| static MYSQL_ROW fetch_varlength_columns(STMT *stmt, MYSQL_ROW columns) |
| { |
| { |
| const unsigned int num_fields= field_count(stmt); |
| const unsigned int num_fields= field_count(stmt); |
| unsigned int i; |
| unsigned int i; |
| |
| |
| for (i= 0; i < num_fields; ++i) |
| for (i= 0; i < num_fields; ++i) |
| { |
| { |
| if (stmt->result_bind[i].buffer == NULL) |
| if (stmt->result_bind[i].buffer == NULL) |
| { |
| { |
| if (stmt->lengths[i] < *stmt->result_bind[i].length) |
| if (stmt->lengths[i] < *stmt->result_bind[i].length) |
| { |
| { |
| /* TODO Realloc error proc */ |
| /* TODO Realloc error proc */ |
| stmt->array[i] = my_realloc(stmt->array[i], *stmt->result_bind[i].length, |
| stmt->array[i] = my_realloc(stmt->array[i], *stmt->result_bind[i].length, |
| MYF(MY_ALLOW_ZERO_PTR)); |
| MYF(MY_ALLOW_ZERO_PTR)); |
| stmt->lengths[i]= *stmt->result_bind[i].length; |
| stmt->lengths[i]= *stmt->result_bind[i].length; |
| } |
| } |
| |
| |
| stmt->result_bind[i].buffer= stmt->array[i]; |
| stmt->result_bind[i].buffer= stmt->array[i]; |
| stmt->result_bind[i].buffer_length= stmt->lengths[i]; |
| stmt->result_bind[i].buffer_length= stmt->lengths[i]; |
| |
| |
| mysql_stmt_fetch_column(stmt->ssps, &stmt->result_bind[i], i, 0); |
| mysql_stmt_fetch_column(stmt->ssps, &stmt->result_bind[i], i, 0); |
| } |
| } |
| } |
| } |
| |
| |
| fill_ird_data_lengths(stmt->ird, stmt->result_bind[0].length, |
| fill_ird_data_lengths(stmt->ird, stmt->result_bind[0].length, |
| stmt->result->field_count); |
| stmt->result->field_count); |
| |
| |
| return stmt->array; |
| return stmt->array; |
| } |
| } |
| |
| |
| |
| |
| int ssps_bind_result(STMT *stmt) |
| int ssps_bind_result(STMT *stmt) |
| { |
| { |
| const unsigned int num_fields= field_count(stmt); |
| const unsigned int num_fields= field_count(stmt); |
| unsigned int i; |
| unsigned int i; |
| |
| |
| if (num_fields == 0) |
| if (num_fields == 0) |
| { |
| { |
| return 0; |
| return 0; |
| } |
| } |
| |
| |
| if (stmt->result_bind) |
| if (stmt->result_bind) |
| { |
| { |
| /* We have fields requiring to read real length first */ |
| /* We have fields requiring to read real length first */ |
| if (stmt->fix_fields != NULL) |
| if (stmt->fix_fields != NULL) |
| { |
| { |
| for (i=0; i < num_fields; ++i) |
| for (i=0; i < num_fields; ++i) |
| { |
| { |
| /* length marks such fields */ |
| /* length marks such fields */ |
| if (stmt->lengths[i] > 0) |
| if (stmt->lengths[i] > 0) |
| { |
| { |
| /* Resetting buffer and buffer_length for those fields */ |
| /* Resetting buffer and buffer_length for those fields */ |
| stmt->result_bind[i].buffer = 0; |
| stmt->result_bind[i].buffer = 0; |
| stmt->result_bind[i].buffer_length= 0; |
| stmt->result_bind[i].buffer_length= 0; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| else |
| else |
| { |
| { |
| my_bool *is_null= my_malloc(sizeof(my_bool)*num_fields, |
| my_bool *is_null= my_malloc(sizeof(my_bool)*num_fields, |
| MYF(MY_ZEROFILL)); |
| MYF(MY_ZEROFILL)); |
| my_bool *err= my_malloc(sizeof(my_bool)*num_fields, |
| my_bool *err= my_malloc(sizeof(my_bool)*num_fields, |
| MYF(MY_ZEROFILL)); |
| MYF(MY_ZEROFILL)); |
| unsigned long *len= my_malloc(sizeof(unsigned long)*num_fields, |
| unsigned long *len= my_malloc(sizeof(unsigned long)*num_fields, |
| MYF(MY_ZEROFILL)); |
| MYF(MY_ZEROFILL)); |
| |
| |
| /*TODO care about memory allocation errors */ |
| /*TODO care about memory allocation errors */ |
| stmt->result_bind= (MYSQL_BIND*)my_malloc(sizeof(MYSQL_BIND)*num_fields, |
| stmt->result_bind= (MYSQL_BIND*)my_malloc(sizeof(MYSQL_BIND)*num_fields, |
| MYF(MY_ZEROFILL)); |
| MYF(MY_ZEROFILL)); |
| stmt->array= (MYSQL_ROW)my_malloc(sizeof(char*)*num_fields, |
| stmt->array= (MYSQL_ROW)my_malloc(sizeof(char*)*num_fields, |
| MYF(MY_ZEROFILL)); |
| MYF(MY_ZEROFILL)); |
| |
| |
| for (i= 0; i < num_fields; ++i) |
| for (i= 0; i < num_fields; ++i) |
| { |
| { |
| MYSQL_FIELD *field= mysql_fetch_field_direct(stmt->result, i); |
| MYSQL_FIELD *field= mysql_fetch_field_direct(stmt->result, i); |
| st_buffer_size_type p= allocate_buffer_for_field(field, |
| st_buffer_size_type p= allocate_buffer_for_field(field, |
| IS_PS_OUT_PARAMS(stmt)); |
| IS_PS_OUT_PARAMS(stmt)); |
| |
| |
| stmt->result_bind[i].buffer_type = p.type; |
| stmt->result_bind[i].buffer_type = p.type; |
| stmt->result_bind[i].buffer = p.buffer; |
| stmt->result_bind[i].buffer = p.buffer; |
| stmt->result_bind[i].buffer_length= (unsigned long)p.size; |
| stmt->result_bind[i].buffer_length= (unsigned long)p.size; |
| stmt->result_bind[i].length = &len[i]; |
| stmt->result_bind[i].length = &len[i]; |
| stmt->result_bind[i].is_null = &is_null[i]; |
| stmt->result_bind[i].is_null = &is_null[i]; |
| stmt->result_bind[i].error = &err[i]; |
| stmt->result_bind[i].error = &err[i]; |
| stmt->result_bind[i].is_unsigned = (field->flags & UNSIGNED_FLAG)? 1: 0; |
| stmt->result_bind[i].is_unsigned = (field->flags & UNSIGNED_FLAG)? 1: 0; |
| |
| |
| stmt->array[i]= p.buffer; |
| stmt->array[i]= p.buffer; |
| |
| |
| /* Marking that there are columns that will require buffer (re) allocating |
| /* Marking that there are columns that will require buffer (re) allocating |
| */ |
| */ |
| if ( stmt->result_bind[i].buffer == 0 |
| if ( stmt->result_bind[i].buffer == 0 |
| && stmt->result_bind[i].buffer_type != MYSQL_TYPE_NULL) |
| && stmt->result_bind[i].buffer_type != MYSQL_TYPE_NULL) |
| { |
| { |
| stmt->fix_fields= fetch_varlength_columns; |
| stmt->fix_fields= fetch_varlength_columns; |
| |
| |
| /* Need to alloc it only once*/ |
| /* Need to alloc it only once*/ |
| if (stmt->lengths == NULL) |
| if (stmt->lengths == NULL) |
| { |
| { |
| stmt->lengths= my_malloc(sizeof(unsigned long)*num_fields, MYF(MY_ZEROFILL)); |
| stmt->lengths= my_malloc(sizeof(unsigned long)*num_fields, MYF(MY_ZEROFILL)); |
| } |
| } |
| /* Buffer of initial length? */ |
| /* Buffer of initial length? */ |
| } |
| } |
| } |
| } |
| |
| |
| return mysql_stmt_bind_result(stmt->ssps, stmt->result_bind); |
| return mysql_stmt_bind_result(stmt->ssps, stmt->result_bind); |
| } |
| } |
| |
| |
| return 0; |
| return 0; |
| } |
| } |
| |
| |
| |
| |
| BOOL ssps_0buffers_truncated_only(STMT *stmt) |
| BOOL ssps_0buffers_truncated_only(STMT *stmt) |
| { |
| { |
| if (stmt->fix_fields == NULL) |
| if (stmt->fix_fields == NULL) |
| { |
| { |
| /* That is enough to tell that not */ |
| /* That is enough to tell that not */ |
| return FALSE; |
| return FALSE; |
| } |
| } |
| else |
| else |
| { |
| { |
| const unsigned int num_fields= field_count(stmt); |
| const unsigned int num_fields= field_count(stmt); |
| unsigned int i; |
| unsigned int i; |
| |
| |
| for (i= 0; i < num_fields; ++i) |
| for (i= 0; i < num_fields; ++i) |
| { |
| { |
| if (*stmt->result_bind[i].error != 0 |
| if (*stmt->result_bind[i].error != 0 |
| && stmt->result_bind[i].buffer_length > 0 |
| && stmt->result_bind[i].buffer_length > 0 |
| && stmt->result_bind[i].buffer != NULL) |
| && stmt->result_bind[i].buffer != NULL) |
| { |
| { |
| return FALSE; |
| return FALSE; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| return TRUE; |
| return TRUE; |
| } |
| } |
| |
| |
| |
| |
| /* --------------- Type conversion functions -------------- */ |
| /* --------------- Type conversion functions -------------- */ |
| |
| |
| #define ALLOC_IFNULL(buff,size) ((buff)==NULL?(char*)my_malloc(size,MYF(0)):buff) |
| #define ALLOC_IFNULL(buff,size) ((buff)==NULL?(char*)my_malloc(size,MYF(0)):buff) |
| |
| |
| /* {{{ Prepared ResultSet ssps_get_string() -I- */ |
| /* {{{ Prepared ResultSet ssps_get_string() -I- */ |
| /* caller should care to make buffer long enough, |
| /* caller should care to make buffer long enough, |
| if buffer is not null function allocates memory and that is caller's duty to clean it |
| if buffer is not null function allocates memory and that is caller's duty to clean it |
| */ |
| */ |
| char * ssps_get_string(STMT *stmt, ulong column_number, char *value, ulong *length, |
| char * ssps_get_string(STMT *stmt, ulong column_number, char *value, ulong *length, |
| char * buffer) |
| char * buffer) |
| { |
| { |
| MYSQL_BIND *col_rbind= &stmt->result_bind[column_number]; |
| MYSQL_BIND *col_rbind= &stmt->result_bind[column_number]; |
| |
| |
| if (*col_rbind->is_null) |
| if (*col_rbind->is_null) |
| { |
| { |
| return NULL; |
| return NULL; |
| } |
| } |
| |
| |
| switch (col_rbind->buffer_type) |
| switch (col_rbind->buffer_type) |
| { |
| { |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_DATETIME: |
| case MYSQL_TYPE_DATETIME: |
| { |
| { |
| MYSQL_TIME * t = (MYSQL_TIME *)(col_rbind->buffer); |
| MYSQL_TIME * t = (MYSQL_TIME *)(col_rbind->buffer); |
| |
| |
| buffer= ALLOC_IFNULL(buffer, 30); |
| buffer= ALLOC_IFNULL(buffer, 30); |
| snprintf(buffer, 20, "%04u-%02u-%02u %02u:%02u:%02u", |
| snprintf(buffer, 20, "%04u-%02u-%02u %02u:%02u:%02u", |
| t->year, t->month, t->day, t->hour, t->minute, t->second); |
| t->year, t->month, t->day, t->hour, t->minute, t->second); |
| |
| |
| *length= 19; |
| *length= 19; |
| |
| |
| if (t->second_part > 0) |
| if (t->second_part > 0) |
| { |
| { |
| snprintf(buffer+*length, 8, ".%06lu", t->second_part); |
| snprintf(buffer+*length, 8, ".%06lu", t->second_part); |
| *length= 26; |
| *length= 26; |
| } |
| } |
| |
| |
| return buffer; |
| return buffer; |
| } |
| } |
| case MYSQL_TYPE_DATE: |
| case MYSQL_TYPE_DATE: |
| { |
| { |
| MYSQL_TIME * t = (MYSQL_TIME *)(col_rbind->buffer); |
| MYSQL_TIME * t = (MYSQL_TIME *)(col_rbind->buffer); |
| |
| |
| buffer= ALLOC_IFNULL(buffer, 12); |
| buffer= ALLOC_IFNULL(buffer, 12); |
| snprintf(buffer, 11, "%04u-%02u-%02u", t->year, t->month, t->day); |
| snprintf(buffer, 11, "%04u-%02u-%02u", t->year, t->month, t->day); |
| *length= 10; |
| *length= 10; |
| |
| |
| return buffer; |
| return buffer; |
| } |
| } |
| case MYSQL_TYPE_TIME: |
| case MYSQL_TYPE_TIME: |
| { |
| { |
| MYSQL_TIME * t = (MYSQL_TIME *)(col_rbind->buffer); |
| MYSQL_TIME * t = (MYSQL_TIME *)(col_rbind->buffer); |
| |
| |
| buffer= ALLOC_IFNULL(buffer, 20); |
| buffer= ALLOC_IFNULL(buffer, 20); |
| snprintf(buffer, 10, "%s%02u:%02u:%02u", t->neg? "-":"", t->hour, |
| snprintf(buffer, 10, "%s%02u:%02u:%02u", t->neg? "-":"", t->hour, |
| t->minute, t->second); |
| t->minute, t->second); |
| *length= t->neg ? 9 : 8; |
| *length= t->neg ? 9 : 8; |
| |
| |
| if (t->second_part > 0) |
| if (t->second_part > 0) |
| { |
| { |
| snprintf(buffer+*length, 8, ".%06lu", t->second_part); |
| snprintf(buffer+*length, 8, ".%06lu", t->second_part); |
| *length+= 7; |
| *length+= 7; |
| } |
| } |
| return buffer; |
| return buffer; |
| } |
| } |
| case MYSQL_TYPE_BIT: |
| case MYSQL_TYPE_BIT: |
| case MYSQL_TYPE_YEAR: // fetched as a SMALLINT |
| case MYSQL_TYPE_YEAR: // fetched as a SMALLINT |
| case MYSQL_TYPE_TINY: |
| case MYSQL_TYPE_TINY: |
| case MYSQL_TYPE_SHORT: |
| case MYSQL_TYPE_SHORT: |
| case MYSQL_TYPE_INT24: |
| case MYSQL_TYPE_INT24: |
| case MYSQL_TYPE_LONG: |
| case MYSQL_TYPE_LONG: |
| case MYSQL_TYPE_LONGLONG: |
| case MYSQL_TYPE_LONGLONG: |
| { |
| { |
| buffer= ALLOC_IFNULL(buffer, 30); |
| buffer= ALLOC_IFNULL(buffer, 30); |
| |
| |
| if (col_rbind->is_unsigned) |
| if (col_rbind->is_unsigned) |
| { |
| { |
| my_ul_to_a(buffer, 29, |
| my_ul_to_a(buffer, 29, |
| (unsigned long long)ssps_get_int64(stmt, column_number, value, *length)); |
| (unsigned long long)ssps_get_int64(stmt, column_number, value, *length)); |
| } |
| } |
| else |
| else |
| { |
| { |
| my_l_to_a(buffer, 29, |
| my_l_to_a(buffer, 29, |
| ssps_get_int64(stmt, column_number, value, *length)); |
| ssps_get_int64(stmt, column_number, value, *length)); |
| } |
| } |
| |
| |
| *length= strlen(buffer); |
| *length= strlen(buffer); |
| return buffer; |
| return buffer; |
| } |
| } |
| case MYSQL_TYPE_FLOAT: |
| case MYSQL_TYPE_FLOAT: |
| case MYSQL_TYPE_DOUBLE: |
| case MYSQL_TYPE_DOUBLE: |
| { |
| { |
| buffer= ALLOC_IFNULL(buffer, 50); |
| buffer= ALLOC_IFNULL(buffer, 50); |
| my_f_to_a(buffer, 49, ssps_get_double(stmt, column_number, value, |
| my_f_to_a(buffer, 49, ssps_get_double(stmt, column_number, value, |
| *length)); |
| *length)); |
| |
| |
| *length= strlen(buffer); |
| *length= strlen(buffer); |
| return buffer; |
| return buffer; |
| } |
| } |
| |
| |
| case MYSQL_TYPE_DECIMAL: |
| case MYSQL_TYPE_DECIMAL: |
| case MYSQL_TYPE_NEWDECIMAL: |
| case MYSQL_TYPE_NEWDECIMAL: |
| case MYSQL_TYPE_STRING: |
| case MYSQL_TYPE_STRING: |
| case MYSQL_TYPE_LONG_BLOB: |
| case MYSQL_TYPE_LONG_BLOB: |
| case MYSQL_TYPE_BLOB: |
| case MYSQL_TYPE_BLOB: |
| case MYSQL_TYPE_VARCHAR: |
| case MYSQL_TYPE_VARCHAR: |
| case MYSQL_TYPE_VAR_STRING: |
| case MYSQL_TYPE_VAR_STRING: |
| *length= *col_rbind->length; |
| *length= *col_rbind->length; |
| return (char *)(col_rbind->buffer); |
| return (char *)(col_rbind->buffer); |
| default: |
| default: |
| break; |
| break; |
| // TODO : Geometry? default ? |
| // TODO : Geometry? default ? |
| } |
| } |
| |
| |
| /* Basically should be prevented by earlied tests of |
| /* Basically should be prevented by earlied tests of |
| conversion possibility */ |
| conversion possibility */ |
| return col_rbind->buffer; |
| return col_rbind->buffer; |
| } |
| } |
| /* }}} */ |
| /* }}} */ |
| |
| |
| |
| |
| long double ssps_get_double(STMT *stmt, ulong column_number, char *value, ulong length) |
| long double ssps_get_double(STMT *stmt, ulong column_number, char *value, ulong length) |
| { |
| { |
| MYSQL_BIND *col_rbind= &stmt->result_bind[column_number]; |
| MYSQL_BIND *col_rbind= &stmt->result_bind[column_number]; |
| |
| |
| if (*col_rbind->is_null) |
| if (*col_rbind->is_null) |
| { |
| { |
| return 0.0; |
| return 0.0; |
| } |
| } |
| |
| |
| switch (col_rbind->buffer_type) { |
| switch (col_rbind->buffer_type) { |
| case MYSQL_TYPE_BIT: |
| case MYSQL_TYPE_BIT: |
| case MYSQL_TYPE_YEAR: // fetched as a SMALLINT |
| case MYSQL_TYPE_YEAR: // fetched as a SMALLINT |
| case MYSQL_TYPE_TINY: |
| case MYSQL_TYPE_TINY: |
| case MYSQL_TYPE_SHORT: |
| case MYSQL_TYPE_SHORT: |
| case MYSQL_TYPE_INT24: |
| case MYSQL_TYPE_INT24: |
| case MYSQL_TYPE_LONG: |
| case MYSQL_TYPE_LONG: |
| case MYSQL_TYPE_LONGLONG: |
| case MYSQL_TYPE_LONGLONG: |
| { |
| { |
| long double ret; |
| long double ret; |
| BOOL is_it_unsigned = col_rbind->is_unsigned != 0; |
| BOOL is_it_unsigned = col_rbind->is_unsigned != 0; |
| |
| |
| if (is_it_unsigned) |
| if (is_it_unsigned) |
| { |
| { |
| unsigned long long ival = (unsigned long long)ssps_get_int64(stmt, column_number, value, length); |
| unsigned long long ival = (unsigned long long)ssps_get_int64(stmt, column_number, value, length); |
| ret = (long double)(ival); |
| ret = (long double)(ival); |
| } |
| } |
| else |
| else |
| { |
| { |
| long long ival = ssps_get_int64(stmt, column_number, value, length); |
| long long ival = ssps_get_int64(stmt, column_number, value, length); |
| ret = (long double)(ival); |
| ret = (long double)(ival); |
| } |
| } |
| |
| |
| return ret; |
| return ret; |
| } |
| } |
| case MYSQL_TYPE_DECIMAL: |
| case MYSQL_TYPE_DECIMAL: |
| case MYSQL_TYPE_NEWDECIMAL: |
| case MYSQL_TYPE_NEWDECIMAL: |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_DATETIME: |
| case MYSQL_TYPE_DATETIME: |
| case MYSQL_TYPE_DATE: |
| case MYSQL_TYPE_DATE: |
| case MYSQL_TYPE_TIME: |
| case MYSQL_TYPE_TIME: |
| case MYSQL_TYPE_STRING: |
| case MYSQL_TYPE_STRING: |
| case MYSQL_TYPE_BLOB: |
| case MYSQL_TYPE_BLOB: |
| case MYSQL_TYPE_VARCHAR: |
| case MYSQL_TYPE_VARCHAR: |
| case MYSQL_TYPE_VAR_STRING: |
| case MYSQL_TYPE_VAR_STRING: |
| { |
| { |
| char buf[50]; |
| char buf[50]; |
| long double ret = strtold(ssps_get_string(stmt, column_number, value, |
| long double ret = strtold(ssps_get_string(stmt, column_number, value, |
| &length, buf), NULL); |
| &length, buf), NULL); |
| return ret; |
| return ret; |
| } |
| } |
| |
| |
| case MYSQL_TYPE_FLOAT: |
| case MYSQL_TYPE_FLOAT: |
| { |
| { |
| long double ret = !*col_rbind->is_null? *(float *)(col_rbind->buffer):0.; |
| long double ret = !*col_rbind->is_null? *(float *)(col_rbind->buffer):0.; |
| return ret; |
| return ret; |
| } |
| } |
| |
| |
| case MYSQL_TYPE_DOUBLE: |
| case MYSQL_TYPE_DOUBLE: |
| { |
| { |
| long double ret = !*col_rbind->is_null? *(double *)(col_rbind->buffer):0.; |
| long double ret = !*col_rbind->is_null? *(double *)(col_rbind->buffer):0.; |
| return ret; |
| return ret; |
| } |
| } |
| |
| |
| /* TODO : Geometry? default ? */ |
| /* TODO : Geometry? default ? */ |
| } |
| } |
| |
| |
| /* Basically should be prevented by earlied tests of |
| /* Basically should be prevented by earlied tests of |
| conversion possibility */ |
| conversion possibility */ |
| return .0; |
| return .0; |
| } |
| } |
| |
| |
| |
| |
| /* {{{ Prepared ResultSet ssps_get_int64() -I- */ |
| /* {{{ Prepared ResultSet ssps_get_int64() -I- */ |
| long long ssps_get_int64(STMT *stmt, ulong column_number, char *value, ulong length) |
| long long ssps_get_int64(STMT *stmt, ulong column_number, char *value, ulong length) |
| { |
| { |
| MYSQL_BIND *col_rbind= &stmt->result_bind[column_number]; |
| MYSQL_BIND *col_rbind= &stmt->result_bind[column_number]; |
| |
| |
| switch (col_rbind->buffer_type) |
| switch (col_rbind->buffer_type) |
| { |
| { |
| case MYSQL_TYPE_FLOAT: |
| case MYSQL_TYPE_FLOAT: |
| case MYSQL_TYPE_DOUBLE: |
| case MYSQL_TYPE_DOUBLE: |
| |
| |
| return (long long)ssps_get_double(stmt, column_number, value, length); |
| return (long long)ssps_get_double(stmt, column_number, value, length); |
| |
| |
| case MYSQL_TYPE_DECIMAL: |
| case MYSQL_TYPE_DECIMAL: |
| case MYSQL_TYPE_NEWDECIMAL: |
| case MYSQL_TYPE_NEWDECIMAL: |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_TIMESTAMP: |
| case MYSQL_TYPE_DATETIME: |
| case MYSQL_TYPE_DATETIME: |
| case MYSQL_TYPE_DATE: |
| case MYSQL_TYPE_DATE: |
| case MYSQL_TYPE_TIME: |
| case MYSQL_TYPE_TIME: |
| case MYSQL_TYPE_STRING: |
| case MYSQL_TYPE_STRING: |
| case MYSQL_TYPE_BLOB: |
| case MYSQL_TYPE_BLOB: |
| case MYSQL_TYPE_VARCHAR: |
| case MYSQL_TYPE_VARCHAR: |
| case MYSQL_TYPE_VAR_STRING: |
| case MYSQL_TYPE_VAR_STRING: |
| { |
| { |
| char buf[30]; |
| char buf[30]; |
| return strtoll(ssps_get_string(stmt, column_number, value, &length, buf), |
| return strtoll(ssps_get_string(stmt, column_number, value, &length, buf), |
| NULL, 10); |
| NULL, 10); |
| } |
| } |
| case MYSQL_TYPE_BIT: |
| case MYSQL_TYPE_BIT: |
| { |
| { |
| long long uval = 0; |
| long long uval = 0; |
| /* This length is in bytes, on the contrary to what can be seen in mysql_resultset.cpp where the Meta is used */ |
| /* This length is in bytes, on the contrary to what can be seen in mysql_resultset.cpp where the Meta is used */ |
| return binary2numeric(&uval, col_rbind->buffer, *col_rbind->length); |
| return binary2numeric(&uval, col_rbind->buffer, *col_rbind->length); |
| } |
| } |
| |
| |
| case MYSQL_TYPE_YEAR: // fetched as a SMALLINT |
| case MYSQL_TYPE_YEAR: // fetched as a SMALLINT |
| case MYSQL_TYPE_TINY: |
| case MYSQL_TYPE_TINY: |
| case MYSQL_TYPE_SHORT: |
| case MYSQL_TYPE_SHORT: |
| case MYSQL_TYPE_INT24: |
| case MYSQL_TYPE_INT24: |
| case MYSQL_TYPE_LONG: |
| case MYSQL_TYPE_LONG: |
| case MYSQL_TYPE_LONGLONG: |
| case MYSQL_TYPE_LONGLONG: |
| { |
| { |
| // MYSQL_TYPE_YEAR is fetched as a SMALLINT, thus should not be in the switch |
| // MYSQL_TYPE_YEAR is fetched as a SMALLINT, thus should not be in the switch |
| long long ret; |
| long long ret; |
| BOOL is_it_null = *col_rbind->is_null != 0; |
| BOOL is_it_null = *col_rbind->is_null != 0; |
| BOOL is_it_unsigned = col_rbind->is_unsigned != 0; |
| BOOL is_it_unsigned = col_rbind->is_unsigned != 0; |
| |
| |
| switch (col_rbind->buffer_length) |
| switch (col_rbind->buffer_length) |
| { |
| { |
| case 1: |
| case 1: |
| if (is_it_unsigned) |
| if (is_it_unsigned) |
| { |
| { |
| ret = !is_it_null? ((char *)col_rbind->buffer)[0]:0; |
| ret = !is_it_null? ((char *)col_rbind->buffer)[0]:0; |
| } |
| } |
| else |
| else |
| { |
| { |
| ret = !is_it_null? *(char *)(col_rbind->buffer):0; |
| ret = !is_it_null? *(char *)(col_rbind->buffer):0; |
| } |
| } |
| break; |
| break; |
| |
| |
| case 2: |
| case 2: |
| |
| |
| if (is_it_unsigned) |
| if (is_it_unsigned) |
| { |
| { |
| ret = !is_it_null? *(unsigned short *)(col_rbind->buffer):0; |
| ret = !is_it_null? *(unsigned short *)(col_rbind->buffer):0; |
| } |
| } |
| else |
| else |
| { |
| { |
| ret = !is_it_null? *(short *)(col_rbind->buffer):0; |
| ret = !is_it_null? *(short *)(col_rbind->buffer):0; |
| } |
| } |
| break; |
| break; |
| |
| |
| case 4: |
| case 4: |
| |
| |
| if (is_it_unsigned) |
| if (is_it_unsigned) |
| { |
| { |
| ret = !is_it_null? *(unsigned int *)(col_rbind->buffer):0; |
| ret = !is_it_null? *(unsigned int *)(col_rbind->buffer):0; |
| } |
| } |
| else |
| else |
| { |
| { |
| ret = !is_it_null? *(int *)(col_rbind->buffer):0; |
| ret = !is_it_null? *(int *)(col_rbind->buffer):0; |
| } |
| } |
| break; |
| break; |
| |
| |
| case 8: |
| case 8: |
| |
| |
| if (is_it_unsigned) |
| if (is_it_unsigned) |
| { |
| { |
| ret = !is_it_null? *(unsigned long long *)col_rbind->buffer:0; |
| ret = !is_it_null? *(unsigned long long *)col_rbind->buffer:0; |
| |
| |
| #if WE_WANT_TO_SEE_MORE_FAILURES_IN_UNIT_RESULTSET |
| #if WE_WANT_TO_SEE_MORE_FAILURES_IN_UNIT_RESULTSET |
| if (cutTooBig && |
| if (cutTooBig && |
| ret && |
| ret && |
| *(unsigned long long *)(col_rbind->buffer) > UL64(9223372036854775807)) |
| *(unsigned long long *)(col_rbind->buffer) > UL64(9223372036854775807)) |
| { |
| { |
| ret = UL64(9223372036854775807); |
| ret = UL64(9223372036854775807); |
| } |
| } |
| #endif |
| #endif |
| } |
| } |
| else |
| else |
| { |
| { |
| ret = !is_it_null? *(long long *)(col_rbind->buffer):0; |
| ret = !is_it_null? *(long long *)(col_rbind->buffer):0; |
| } |
| } |
| break; |
| break; |
| default: |
| default: |
| return 0; |
| return 0; |
| } |
| } |
| return ret; |
| return ret; |
| } |
| } |
| default: |
| default: |
| break;/* Basically should be prevented by earlied tests of |
| break;/* Basically should be prevented by earlied tests of |
| conversion possibility */ |
| conversion possibility */ |
| /* TODO : Geometry? default ? */ |
| /* TODO : Geometry? default ? */ |
| } |
| } |
| |
| |
| return 0; // fool compilers |
| return 0; // fool compilers |
| } |
| } |
| /* }}} */ |
| /* }}} */ |
| |
| |