So, I have a workaround that does the job (however, I'm still curious as to why the SQL Processor wouldn't output the necessary attributes correctly). The solution was to have the SQL Processor create the <document>
tag with no attributes, then send that thru the XSLT Processor to add the attributes using a stylesheet.
The new .xpl:
<p:config xmlns:p="http://www.orbeon.com/oxf/pipeline"
xmlns:sql="http://orbeon.org/oxf/xml/sql"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:oxf="http://www.orbeon.com/oxf/processors"
xmlns:xi="http://www.w3.org/2001/XInclude">
<p:processor name="oxf:sql">
<p:input name="datasource" href="/config/datasource-sql.xml"/>
<p:input name="config">
<sql:config>
<document>
<sql:connection>
<sql:execute>
<sql:query>
select blob_col from blob_table where rownum = 1
</sql:query>
<sql:result-set>
<sql:row-iterator>
<sql:get-column-value column="blob_col"/>
</sql:row-iterator>
</sql:result-set>
</sql:execute>
</sql:connection>
</document>
</sql:config>
</p:input>
<p:output name="data" id="sql-data"/>
</p:processor>
<p:processor name="oxf:xslt">
<p:input name="config">
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="document">
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:base64Binary">
<xsl:apply-templates/>
</document>
</xsl:template>
</xsl:stylesheet>
</p:input>
<p:input name="data" href="#sql-data"/>
<p:output name="data" id="image-data"/>
</p:processor>
<p:processor name="oxf:http-serializer">
<p:input name="config">
<config>
<content-type>image/jpeg</content-type>
<force-content-type>true</force-content-type>
</config>
</p:input>
<p:input name="data" href="#image-data"/>
</p:processor>
</p:config>