diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 3a821a35ea38c..5e0945e0a43de 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -2246,7 +2246,20 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) RETCODE ret; UCHAR d_name[32]; SQLSMALLINT len; + SQLUINTEGER dead = SQL_CD_FALSE; + ret = SQLGetConnectAttr(db_conn->hdbc, + SQL_ATTR_CONNECTION_DEAD, + &dead, 0, NULL); + if (ret == SQL_SUCCESS && dead == SQL_CD_TRUE) { + /* Bail early here, since we know it's gone */ + zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_len); + goto try_and_get_another_connection; + } + /* If the driver doesn't support it, or returns + * false (could be a false positive), fall back + * to the old heuristic. + */ ret = SQLGetInfo(db_conn->hdbc, SQL_DATA_SOURCE_READ_ONLY, d_name, sizeof(d_name), &len); diff --git a/ext/pdo_odbc/odbc_driver.c b/ext/pdo_odbc/odbc_driver.c index 308cf7e10c94d..661cab3c04f8c 100644 --- a/ext/pdo_odbc/odbc_driver.c +++ b/ext/pdo_odbc/odbc_driver.c @@ -396,11 +396,19 @@ static zend_result odbc_handle_check_liveness(pdo_dbh_t *dbh) RETCODE ret; UCHAR d_name[32]; SQLSMALLINT len; + SQLUINTEGER dead = SQL_CD_FALSE; pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; + ret = SQLGetConnectAttr(H->dbc, SQL_ATTR_CONNECTION_DEAD, &dead, 0, NULL); + if (ret == SQL_SUCCESS && dead == SQL_CD_TRUE) { + /* Bail early here, since we know it's gone */ + return FAILURE; + } /* - * SQL_ATTR_CONNECTION_DEAD is tempting, but only in ODBC 3.5, - * and not all drivers implement it properly + * If the driver doesn't support SQL_ATTR_CONNECTION_DEAD, or if + * it returns false (which could be a false positive), fall back + * to using SQL_DATA_SOURCE_READ_ONLY, which isn't semantically + * correct, but works with many drivers. */ ret = SQLGetInfo(H->dbc, SQL_DATA_SOURCE_READ_ONLY, d_name, sizeof(d_name), &len);