bool sqlsrv_param_tvp::send_data_packet()

in source/shared/core_stmt.cpp [3475:3579]


bool sqlsrv_param_tvp::send_data_packet(_Inout_ sqlsrv_stmt* stmt)
{
    if (sql_data_type != SQL_SS_TABLE) {
        // This is one of the constituent columns of the table-valued parameter
        // Check current_row first
        if (current_row >= num_rows) {
            return false;
        }

        // Find the row from the TVP data based on current_row
        zval* row_z = zend_hash_index_find(Z_ARRVAL_P(parent_tvp->param_ptr_z), current_row);
        if (Z_ISREF_P(row_z)) {
            ZVAL_DEREF(row_z);
        }
        // Now find the column value based on param_pos
        zval* value_z = zend_hash_index_find(Z_ARRVAL_P(row_z), param_pos);

        // First check if value_z is NULL
        if (Z_TYPE_P(value_z) == IS_NULL) {
            core::SQLPutData(stmt, NULL, SQL_NULL_DATA);
            current_row++;
        } else {
            switch (param_php_type) {
            case IS_RESOURCE:
                {
                    num_bytes_read = 0;
                    param_stream = NULL;

                    // Get the stream from the zval value
                    core::sqlsrv_php_stream_from_zval_no_verify(*stmt, param_stream, value_z);
                    // Keep sending the packets until EOF is reached
                    while (sqlsrv_param::send_data_packet(stmt)) {
                    }
                    current_row++;
                }
                break;
            case IS_OBJECT:
                {
                    // This method updates placeholder_z as a string
                    bool succeeded = convert_datetime_to_string(stmt, value_z);

                    // Conversion failed so assume the input was an invalid PHP type
                    CHECK_CUSTOM_ERROR(!succeeded, stmt, SQLSRV_ERROR_TVP_INVALID_COLUMN_PHPTYPE, parent_tvp->param_pos + 1, param_pos + 1) {
                        throw core::CoreException();
                    }

                    core::SQLPutData(stmt, Z_STRVAL(placeholder_z), SQL_NTS);
                    current_row++;
                }
                break;
            case IS_STRING:
                {
                    int type = Z_TYPE_P(value_z);
                    if (type != IS_STRING) {
                        convert_to_string(value_z);
                    }
                    SQLLEN value_len = Z_STRLEN_P(value_z);
                    if (value_len == 0) {
                        // If it's an empty string
                        core::SQLPutData(stmt, Z_STRVAL_P(value_z), 0);
                    } else {
                        if (encoding == CP_UTF8 && !is_a_numeric_type(sql_data_type)) {
                            if (value_len > INT_MAX) {
                                LOG(SEV_ERROR, "Convert input parameter to utf16: buffer length exceeded.");
                                throw core::CoreException();
                            }
                            // This method would change the member placeholder_z
                            bool succeeded = convert_input_str_to_utf16(stmt, value_z);
                            CHECK_CUSTOM_ERROR(!succeeded, stmt, SQLSRV_ERROR_TVP_STRING_ENCODING_TRANSLATE, parent_tvp->param_pos + 1, param_pos + 1, get_last_error_message()) {
                                throw core::CoreException();
                            }

                            send_string_data_in_batches(stmt, &placeholder_z);
                        } else {
                            send_string_data_in_batches(stmt, value_z);
                        }
                    }
                    current_row++;
                }
                break;
            default:
                // Do nothing for basic types as they should be processed elsewhere
                break;
            }
        } // else not IS_NULL
    } else {
        // This is the table-valued parameter
        if (current_row < num_rows) {
            // Loop through the table parameter columns and populate each cell's placeholder whenever applicable
            for (size_t i = 0; i < tvp_columns.size(); i++) {
                tvp_columns[i]->populate_cell_placeholder(stmt, current_row);
            }

            // This indicates a TVP row is available
            core::SQLPutData(stmt, reinterpret_cast<SQLPOINTER>(1), 1);
            current_row++;
        } else {
            // This indicates there is no more TVP row
            core::SQLPutData(stmt, reinterpret_cast<SQLPOINTER>(0), 0);
        }
    }

    // Return false to indicate that the current row has been sent
    return false;
}