Skip to content

Commit

Permalink
More robust handling of stringified column data
Browse files Browse the repository at this point in the history
 - Use at least the FreeTDS maximum when converting datetime data
 - Pass buffer length to dbconvert()
 - Use dbconvert() return value to set string lengths or handle errors
 - Move shared code into shared function
  • Loading branch information
adambaratz committed Nov 10, 2017
1 parent ca1f07b commit 01f2427
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 19 deletions.
65 changes: 46 additions & 19 deletions ext/pdo_dblib/dblib_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno)
return 1;
}

static int pdo_dblib_stmt_stringify_col(pdo_stmt_t *stmt, int coltype)
static int pdo_dblib_stmt_should_stringify_col(pdo_stmt_t *stmt, int coltype)
{
pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
pdo_dblib_db_handle *H = S->H;
Expand Down Expand Up @@ -305,6 +305,48 @@ static int pdo_dblib_stmt_stringify_col(pdo_stmt_t *stmt, int coltype)
return 0;
}

static void pdo_dblib_stmt_stringify_col(int coltype, LPBYTE data, DBINT data_len, zval **ptr)
{
DBCHAR *tmp_data;
DBINT tmp_data_len;
zval *zv;

/* FIXME: We allocate more than we need here */
tmp_data_len = 32 + (2 * (data_len));

switch (coltype) {
case SQLDATETIME:
case SQLDATETIM4: {
if (tmp_data_len < DATETIME_MAX_LEN) {
tmp_data_len = DATETIME_MAX_LEN;
}
break;
}
}

tmp_data = emalloc(tmp_data_len);
data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, tmp_data_len);

zv = emalloc(sizeof(zval));
if (data_len > 0) {
/* to prevent overflows, tmp_data_len is provided as a dest len for dbconvert()
* this code previously passed a dest len of -1
* the FreeTDS impl of dbconvert() does an rtrim with that value, so replicate that behavior
*/
while (data_len > 0 && tmp_data[data_len - 1] == ' ') {
data_len--;
}

ZVAL_STRINGL(zv, tmp_data, data_len);
} else {
ZVAL_EMPTY_STRING(zv);
}

efree(tmp_data);

*ptr = zv;
}

static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
zend_ulong *len, int *caller_frees)
{
Expand All @@ -323,15 +365,8 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
data_len = dbdatlen(H->link, colno+1);

if (data_len != 0 || data != NULL) {
if (pdo_dblib_stmt_stringify_col(stmt, coltype) && dbwillconvert(coltype, SQLCHAR)) {
tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */
tmp_data = emalloc(tmp_data_len);
data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, -1);

zv = emalloc(sizeof(zval));
ZVAL_STRING(zv, tmp_data);

efree(tmp_data);
if (pdo_dblib_stmt_should_stringify_col(stmt, coltype) && dbwillconvert(coltype, SQLCHAR)) {
pdo_dblib_stmt_stringify_col(coltype, data, data_len, &zv);
}

if (!zv) {
Expand Down Expand Up @@ -438,7 +473,6 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
zv = emalloc(sizeof(zval));
ZVAL_STRINGL(zv, tmp_data, data_len);
efree(tmp_data);

} else {
/* 16-byte binary representation */
zv = emalloc(sizeof(zval));
Expand All @@ -449,14 +483,7 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,

default: {
if (dbwillconvert(coltype, SQLCHAR)) {
tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */
tmp_data = emalloc(tmp_data_len);
data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, -1);

zv = emalloc(sizeof(zval));
ZVAL_STRING(zv, tmp_data);

efree(tmp_data);
pdo_dblib_stmt_stringify_col(coltype, data, data_len, &zv);
}

break;
Expand Down
4 changes: 4 additions & 0 deletions ext/pdo_dblib/php_pdo_dblib_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ typedef unsigned char *LPBYTE;
typedef float DBFLT4;
#endif

// hardcoded string length from FreeTDS
// src/tds/convert.c:tds_convert_datetimeall()
# define DATETIME_MAX_LEN 63

int pdo_dblib_error_handler(DBPROCESS *dbproc, int severity, int dberr,
int oserr, char *dberrstr, char *oserrstr);

Expand Down

0 comments on commit 01f2427

Please sign in to comment.