1

I have a varbinary(8000) database field in SQL Server that I want to pull out. The sqlsrv limit for varbinary data is 8000.

However if I do a select on the data

<?php
$query = "
    SELECT myvarbinary
    FROM   table
    WHERE  id = 48033;
";
$results = sqlsrv_query($this->conn, $query);
return sqlsrv_fetch_array($results, SQLSRV_FETCH_NUMERIC);

Then the sqlsrv_fetch_array gives an error:

PHP Fatal error: Invalid sql_display_size

Truncation solution (works but no use)

If I convert the field to varbinary(4000) then it works, but varbinary(4001) fails:

<?php
$query = "
    SELECT CAST(myvarbinary AS varbinary(4000)) AS myvarbinary
    FROM   table
    WHERE  id = 48033;
";
$results = sqlsrv_query($this->conn, $query);
return sqlsrv_fetch_array($results, SQLSRV_FETCH_NUMERIC);

However this is no use - I'm truncating half the data.

This also implies that for some reason, although the limit is supposed to be 8000, the sqlsrv library is for some reason doubling the value when it checks against the max allowed field size.

MAX solution - will this fully return the 8000 bytes or is it just silently truncating it?

I can also use varbinary(max) which works.

<?php
$query = "
    SELECT CAST(myvarbinary AS varbinary(max)) AS myvarbinary
    FROM   table
    WHERE  id = 48033;
";
$results = sqlsrv_query($this->conn, $query);
return sqlsrv_fetch_array($results, SQLSRV_FETCH_NUMERIC);

In testing the data that gets returned from sqlsrv I can't prove that it is truncating the data or not. So I think this solution works, but I can't be certain.

Can anyone give me a bit more faith that sqlsrv isn't truncating my data down to 4000 bytes?


Edit: This technet documentation indicates that if you want to transfer images larger than 8KB then you should use varbinary(max)

In this section, we examine code in the Example Application that sends an image to the server as a binary stream. The following code opens an image as a stream and then sends the file up to the server in parts up to 8KB at a time:

$tsql = "INSERT INTO Production.ProductPhoto (LargePhoto)
       VALUES (?);
       SELECT SCOPE_IDENTITY() AS PhotoID";
$fileStream = fopen($_FILES['file']['tmp_name'], "r");
$params = array(
   array(
       $fileStream,
       SQLSRV_PARAM_IN,
       SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY),
       SQLSRV_SQLTYPE_VARBINARY('max')
   )
);
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
icc97
  • 11,395
  • 8
  • 76
  • 90
  • Strange... I often read data from `IMAGE` columns of arbitrary size (often larger than that) and I don't need to do anything special. Either you've hit a bug or `VARBINARY` behaves differently. – Álvaro González Nov 30 '16 at 13:21
  • @ÁlvaroGonzález `IMAGE` is a synonym of `VARBINARY(MAX)`, From this [MSDN article](https://msdn.microsoft.com/en-us/library/cc296183(v=sql.105).aspx) the footnote for `SQLSRV_SQLTYPE_IMAGE`, *"This is a legacy type that maps to the varbinary(max) type."* The `varbinary(max)` type is supposed to allow you to have larger than 8000. See this [MSDN article](https://msdn.microsoft.com/en-us/library/ms188362.aspx). *"Use varbinary(max) when the column data entries exceed 8,000 bytes."* But in theory I don't need the varbinary(max). – icc97 Nov 30 '16 at 13:59
  • @ÁlvaroGonzález, thanks for your comment. It maybe that I'm worrying about nothing, and `varbinary(max)` is fine. It's just a bit concerning with 8000 not being handled properly, that I can just stick in 'max' in and there's no issues. You're comment suggests that what I'm doing should be fine. – icc97 Nov 30 '16 at 14:09
  • I've just done quick test and definitively `VARBINARY()` (even `VARBINARY(MAX)`) behaves differently than `IMAGE`. If I run a simple insert I get *Implicit conversion from data type varchar to varbinary is not allowed. Use the CONVERT function to run this query.*, but same code works with `IMAGE` column. Sorry I can't be of more help. – Álvaro González Dec 01 '16 at 09:15
  • @ÁlvaroGonzález hmm interesting. I'm satisfied now that `VARBINARY(max)` is good enough for me, if you just put down your first comment as an answer I'll accept it. As I see it if I want to select anything more than `VARBINARY(4000)` then I just switch to `VARBINARY(max)` and the sqlsrv library handles that without truncating data. For you though it's worth noting that `IMAGE` is definitely going to be removed at some point from SQL Server: https://msdn.microsoft.com/en-us/library/ms187993.aspx – icc97 Dec 01 '16 at 09:34
  • I don't mind the rep: it wouldn't be a good answer. – Álvaro González Dec 02 '16 at 10:16

0 Answers0