DBLargeBinary.java

  1. /*
  2.  * Copyright 2013 Gregory Graham.
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *      http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16. package nz.co.gregs.dbvolution.datatypes;

  17. import java.io.*;
  18. import static java.nio.charset.StandardCharsets.UTF_8;
  19. import java.sql.*;
  20. import java.util.*;
  21. import java.util.logging.*;
  22. import nz.co.gregs.dbvolution.*;
  23. import nz.co.gregs.dbvolution.columns.LargeBinaryColumn;
  24. import nz.co.gregs.dbvolution.databases.definitions.DBDefinition;
  25. import nz.co.gregs.dbvolution.internal.query.LargeObjectHandlerType;
  26. import nz.co.gregs.dbvolution.exceptions.DBRuntimeException;
  27. import nz.co.gregs.dbvolution.exceptions.IncorrectRowProviderInstanceSuppliedException;
  28. import nz.co.gregs.dbvolution.query.RowDefinition;
  29. import nz.co.gregs.dbvolution.utility.comparators.ByteArrayComparator;
  30. import org.apache.commons.codec.binary.Base64;

  31. /**
  32.  *
  33.  * Implements the abstractions necessary to handle arbitrary byte streams and
  34.  * files stored in the database.
  35.  *
  36.  * <p>
  37.  * Use DBLargeBinary for files and streams. Store exceptionally long text in
  38.  * {@link DBLargeText} and Java instances/objects as {@link DBJavaObject} for
  39.  * greater convenience.
  40.  *
  41.  * <p>
  42.  * Generally DBLargeBinary is declared inside your DBRow sub-class as:
  43.  * {@code @DBColumn public DBLargeBinary myBinaryColumn = new DBLargeBinary();}
  44.  *
  45.  * <p>
  46.  * DBLargeBinary is the standard type of {@link DBLargeObject BLOB columns}.
  47.  *
  48.  * <p style="color: #F90;">Support DBvolution at
  49.  * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
  50.  *
  51.  * @author Gregory Graham
  52.  */

  53. import nz.co.gregs.dbvolution.results.LargeBinaryResult;

  54. public class DBLargeBinary extends DBLargeObject<byte[]> implements LargeBinaryResult{

  55.     private static final long serialVersionUID = 1;

  56.     /**
  57.      * The Default constructor for a DBBinaryObject.
  58.      *
  59.      */
  60.     public DBLargeBinary() {
  61.         super();
  62.     }

  63.     /**
  64.      * Creates a column expression with a large object result from the expression
  65.      * provided.
  66.      *
  67.      * <p>
  68.      * Used in {@link DBReport}, and some {@link DBRow}, sub-classes to derive
  69.      * data from the database prior to retrieval.
  70.      *
  71.      * @param aThis an expression that will result in a large object value
  72.      */
  73.     public DBLargeBinary(LargeBinaryResult aThis) {
  74.         super(aThis);
  75.     }

  76.     public DBLargeBinary(byte[] value) {
  77.         super();
  78.         setByteArray(value);
  79.     }

  80.     /**
  81.      *
  82.      * <p style="color: #F90;">Support DBvolution at
  83.      * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
  84.      *
  85.      * @return the standard SQL datatype that corresponds to this QDT as a String
  86.      */
  87.     @Override
  88.     public String getSQLDatatype() {
  89.         return "BLOB";
  90.     }

  91.     /**
  92.      * Sets the value of this DBLargeBinary to the byte array supplied.
  93.      *
  94.      * @param byteArray byteArray
  95.      */
  96.     @Override
  97.     public void setValue(byte[] byteArray) {
  98.         setByteArray(byteArray);
  99.     }

  100.     private void setByteArray(byte[] byteArray) {
  101.         super.setLiteralValue(byteArray);
  102.     }

  103.     /**
  104.      * Sets the value of this DBLargeBinary to the InputStream supplied.
  105.      *
  106.      * <p>
  107.      * The input stream will not be read until the containing DBRow is
  108.      * saved/inserted.
  109.      *
  110.      * @param inputViaStream    inputViaStream
  111.      */
  112.     public void setValue(InputStream inputViaStream) {
  113.         setValue(getBytesFromInputStream(inputViaStream));
  114.     }

  115.     /**
  116.      * Sets the value of this DBLargeBinary to the file supplied.
  117.      *
  118.      * <p>
  119.      * Unlike {@link #setValue(java.io.InputStream) setting an InputStream}, the
  120.      * file is read immediately and stored internally. If you would prefer to
  121.      * delay the reading of the file, wrap the file in a {@link FileInputStream}.
  122.      *
  123.      * @param fileToRead fileToRead
  124.      * @throws java.io.IOException java.io.IOException
  125.      */
  126.     public void setValue(File fileToRead) throws IOException {
  127.         setFromFileSystem(fileToRead);
  128.     }

  129.     /**
  130.      * Set the value of the DBLargeBinary to the String provided.
  131.      *
  132.      * @param string    string
  133.      */
  134.     public void setValue(String string) {
  135.         setValue(string.getBytes(UTF_8));
  136.     }

  137.     void setValue(DBLargeBinary newLiteralValue) {
  138.         setValue(newLiteralValue.getValue());
  139.     }

  140.     private byte[] getFromBinaryStream(ResultSet resultSet, String fullColumnName) throws SQLException {
  141.         byte[] bytes = new byte[]{};
  142.         try (InputStream inputStream = resultSet.getBinaryStream(fullColumnName)) {
  143.             if (inputStream == null) {
  144.                 this.setToNull();
  145.             } else {
  146.                 bytes = getBytesFromInputStream(inputStream);
  147.             }
  148.         } catch (IOException ex) {
  149.             Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  150.         }
  151.         return bytes;
  152.     }

  153.     private byte[] getFromBLOB(ResultSet resultSet, String fullColumnName) throws SQLException {
  154.         byte[] bytes = new byte[]{};
  155.         Blob blob = resultSet.getBlob(fullColumnName);
  156.         if (resultSet.wasNull()) {
  157.             blob = null;
  158.         }
  159.         if (blob == null) {
  160.             this.setToNull();
  161.         } else {
  162.             InputStream inputStream = blob.getBinaryStream();
  163.             bytes = getBytesFromInputStream(inputStream);
  164.             try {
  165.                 inputStream.close();
  166.             } catch (IOException ex) {
  167.                 Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  168.             }
  169.         }
  170.         return bytes;
  171.     }

  172.     private byte[] getBytesFromInputStream(InputStream inputStream) {
  173.         InputStream input = new BufferedInputStream(inputStream);
  174.         List<byte[]> byteArrays = new ArrayList<>();
  175.         try {
  176.             byte[] resultSetBytes;
  177.             final int byteArrayDefaultSize = 100000;
  178.             resultSetBytes = new byte[byteArrayDefaultSize];
  179.             int bytesRead = input.read(resultSetBytes);
  180.             while (bytesRead > 0) {
  181.                 if (bytesRead == byteArrayDefaultSize) {
  182.                     byteArrays.add(resultSetBytes);
  183.                 } else {
  184.                     byte[] shortBytes = new byte[bytesRead];
  185.                     System.arraycopy(resultSetBytes, 0, shortBytes, 0, bytesRead);
  186.                     byteArrays.add(shortBytes);
  187.                 }
  188.                 resultSetBytes = new byte[byteArrayDefaultSize];
  189.                 bytesRead = input.read(resultSetBytes);
  190.             }
  191.         } catch (IOException ex) {
  192.             Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  193.             throw new DBRuntimeException("Failed to read input", ex);
  194.         } finally {
  195.             try {
  196.                 input.close();
  197.             } catch (IOException ex) {
  198.                 Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  199.                 throw new DBRuntimeException("Failed to close input", ex);
  200.             }
  201.         }
  202.         return concatAllByteArrays(byteArrays);
  203.     }

  204.     public static byte[] concatAllByteArrays(List<byte[]> bytes) {
  205.         if (bytes.isEmpty()) {
  206.             return new byte[]{};
  207.         } else {
  208.             byte[] first = bytes.get(0);
  209.             bytes.remove(0);
  210.             byte[][] rest = bytes.toArray(new byte[][]{});
  211.             int totalLength = first.length;
  212.             for (byte[] array : rest) {
  213.                 totalLength += array.length;
  214.             }
  215.             byte[] result = Arrays.copyOf(first, totalLength);
  216.             int offset = first.length;
  217.             for (byte[] array : rest) {
  218.                 System.arraycopy(array, 0, result, offset, array.length);
  219.                 offset += array.length;
  220.             }
  221.             return result;
  222.         }
  223.     }

  224.     private byte[] getFromGetBytes(ResultSet resultSet, String fullColumnName) throws SQLException {
  225.         byte[] bytes = resultSet.getBytes(fullColumnName);
  226.         return bytes;
  227.     }

  228.     private byte[] getFromCharacterReader(ResultSet resultSet, String fullColumnName) throws SQLException {
  229.         byte[] decodeBuffer = new byte[]{};
  230.         Reader inputReader = null;
  231.         try {
  232.             inputReader = resultSet.getCharacterStream(fullColumnName);
  233.         } catch (NullPointerException nullEx) {
  234.             ;// NullPointerException is thrown by a SQLite-JDBC bug sometimes.
  235.         }
  236.         if (inputReader != null) {
  237.             if (resultSet.wasNull()) {
  238.                 this.setToNull();
  239.             } else {
  240.                 BufferedReader input = new BufferedReader(inputReader);
  241.                 List<byte[]> byteArrays = new ArrayList<>();

  242.                 try {
  243.                     char[] resultSetBytes;
  244.                     final int byteArrayDefaultSize = 100000;
  245.                     resultSetBytes = new char[byteArrayDefaultSize];
  246.                     int bytesRead = input.read(resultSetBytes);
  247.                     while (bytesRead > 0) {
  248.                         if (bytesRead == byteArrayDefaultSize) {
  249.                             byteArrays.add(String.valueOf(resultSetBytes).getBytes(UTF_8));
  250.                         } else {
  251.                             char[] shortBytes = new char[bytesRead];
  252.                             System.arraycopy(resultSetBytes, 0, shortBytes, 0, bytesRead);
  253.                             byteArrays.add(String.valueOf(shortBytes).getBytes(UTF_8));
  254.                         }
  255.                         resultSetBytes = new char[byteArrayDefaultSize];
  256.                         bytesRead = input.read(resultSetBytes);
  257.                     }
  258.                 } catch (IOException ex) {
  259.                     Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  260.                     throw new DBRuntimeException("Failed to read input", ex);
  261.                 } finally {
  262.                     try {
  263.                         input.close();
  264.                     } catch (IOException ex) {
  265.                         Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  266.                         throw new DBRuntimeException("Failed to close input", ex);
  267.                     }
  268.                 }
  269.                 byte[] bytes = concatAllByteArrays(byteArrays);
  270.                 decodeBuffer = Base64.decodeBase64(bytes);
  271.             }
  272.         }
  273.         return decodeBuffer;
  274.     }

  275.     private byte[] getFromCLOB(ResultSet resultSet, String fullColumnName) throws SQLException {
  276.         byte[] bytes = new byte[]{};
  277.         Clob clob = resultSet.getClob(fullColumnName);
  278.         if (resultSet.wasNull() || clob == null) {
  279.             this.setToNull();
  280.         } else {
  281.             final Reader characterStream = clob.getCharacterStream();
  282.             try {
  283.                 BufferedReader input = new BufferedReader(characterStream);
  284.                 List<byte[]> byteArrays = new ArrayList<>();

  285.                 try {
  286.                     char[] resultSetBytes;
  287.                     final int byteArrayDefaultSize = 100000;
  288.                     resultSetBytes = new char[byteArrayDefaultSize];
  289.                     int bytesRead = input.read(resultSetBytes);
  290.                     while (bytesRead > 0) {
  291.                         if (bytesRead == byteArrayDefaultSize) {
  292.                             byteArrays.add(String.valueOf(resultSetBytes).getBytes(UTF_8));
  293.                         } else {
  294.                             char[] shortBytes = new char[bytesRead];
  295.                             System.arraycopy(resultSetBytes, 0, shortBytes, 0, bytesRead);
  296.                             byteArrays.add(String.valueOf(shortBytes).getBytes(UTF_8));
  297.                         }
  298.                         resultSetBytes = new char[byteArrayDefaultSize];
  299.                         bytesRead = input.read(resultSetBytes);
  300.                     }
  301.                 } catch (IOException ex) {
  302.                     Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  303.                     throw new DBRuntimeException("Failed to read input", ex);
  304.                 } finally {
  305.                     try {
  306.                         input.close();
  307.                     } catch (IOException ex) {
  308.                         Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  309.                     }
  310.                 }
  311.                 bytes = concatAllByteArrays(byteArrays);
  312.             } finally {
  313.                 try {
  314.                     characterStream.close();
  315.                 } catch (IOException ex) {
  316.                     Logger.getLogger(DBLargeBinary.class.getName()).log(Level.SEVERE, null, ex);
  317.                     throw new DBRuntimeException("Failed to close input", ex);
  318.                 }
  319.             }
  320.         }
  321.         return bytes;
  322.     }

  323.     @Override
  324.     public String formatValueForSQLStatement(DBDefinition db) {
  325.         throw new UnsupportedOperationException("Binary datatypes like " + this.getClass().getSimpleName() + " do not have a simple SQL representation. Do not call getSQLValue(), use the getInputStream() method instead.");
  326.     }

  327.     /**
  328.      * Tries to set the DBDyteArray to the contents of the supplied file.
  329.      *
  330.      * <p>
  331.      * Convenience method for {@link #setFromFileSystem(java.io.File) }.
  332.      *
  333.      * @param originalFile  originalFile
  334.      * <p style="color: #F90;">Support DBvolution at
  335.      * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
  336.      * @throws java.io.FileNotFoundException java.io.FileNotFoundException
  337.      * @throws java.io.IOException java.io.IOException
  338.      *
  339.      *
  340.      */
  341.     public void setFromFileSystem(String originalFile) throws FileNotFoundException, IOException {
  342.         File file = new File(originalFile);
  343.         setFromFileSystem(file);
  344.     }

  345.     /**
  346.      * Tries to set the DBDyteArray to the contents of the supplied file.
  347.      *
  348.      * <p>
  349.      * Convenience method for {@link #setFromFileSystem(java.io.File) }.
  350.      *
  351.      * @param originalFile  originalFile
  352.      * <p style="color: #F90;">Support DBvolution at
  353.      * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
  354.      * @throws java.io.FileNotFoundException java.io.FileNotFoundException
  355.      * @throws java.io.IOException java.io.IOException
  356.      *
  357.      *
  358.      */
  359.     public void setFromFileSystem(DBString originalFile) throws FileNotFoundException, IOException {
  360.         File file = new File(originalFile.stringValue());
  361.         setFromFileSystem(file);
  362.     }

  363.     /**
  364.      * Tries to set the DBDyteArray to the contents of the supplied file.
  365.      *
  366.      * @param originalFile  originalFile
  367.      * <p style="color: #F90;">Support DBvolution at
  368.      * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
  369.      * @throws java.io.FileNotFoundException java.io.FileNotFoundException
  370.      * @throws java.io.IOException java.io.IOException
  371.      *
  372.      *
  373.      */
  374.     private void setFromFileSystem(File originalFile) throws FileNotFoundException, IOException {
  375.         byte[] bytes = new byte[(int) originalFile.length()];
  376.         InputStream input = null;
  377.         try {
  378.             int totalBytesRead = 0;
  379.             input = new BufferedInputStream(new FileInputStream(originalFile));
  380.             while (totalBytesRead < bytes.length) {
  381.                 int bytesRemaining = bytes.length - totalBytesRead;
  382.                 int bytesRead = input.read(bytes, totalBytesRead, bytesRemaining);
  383.                 if (bytesRead > 0) {
  384.                     totalBytesRead += bytesRead;
  385.                 }
  386.             }
  387.             /*
  388.              the above style is a bit tricky: it places bytes into the 'result' array;
  389.              'result' is an output parameter;
  390.              the while loop usually has a single iteration only.
  391.              */
  392.         } finally {
  393.             if (input != null) {
  394.                 input.close();
  395.             }
  396.         }
  397.         setValue(bytes);
  398.     }

  399.     /**
  400.      * Tries to write the contents of this DBLargeBinary to the file supplied.
  401.      *
  402.      * <p>
  403.      * Convenience method for {@link #writeToFileSystem(java.io.File) }.
  404.      *
  405.      * @param originalFile originalFile
  406.      * @throws java.io.FileNotFoundException java.io.FileNotFoundException
  407.      * @throws java.io.IOException java.io.IOException
  408.      */
  409.     public void writeToFileSystem(String originalFile) throws FileNotFoundException, IOException {
  410.         File file = new File(originalFile);
  411.         writeToFileSystem(file);
  412.     }

  413.     /**
  414.      * Tries to write the contents of this DBLargeBinary to the file supplied.
  415.      *
  416.      * <p>
  417.      * Convenience method for {@link #writeToFileSystem(java.io.File) }.
  418.      *
  419.      * @param originalFile originalFile
  420.      * @throws java.io.FileNotFoundException java.io.FileNotFoundException
  421.      * @throws java.io.IOException java.io.IOException
  422.      */
  423.     public void writeToFileSystem(DBString originalFile) throws FileNotFoundException, IOException {
  424.         writeToFileSystem(originalFile.toString());
  425.     }

  426.     /**
  427.      * Tries to write the contents of this DBLargeBinary to the file supplied.
  428.      *
  429.      * <p>
  430.      * Convenience method for {@link #writeToFileSystem(java.io.File) }.
  431.      *
  432.      * @param originalFile originalFile
  433.      * @throws java.io.FileNotFoundException java.io.FileNotFoundException
  434.      * @throws java.io.IOException java.io.IOException
  435.      */
  436.     public void writeToFileSystem(File originalFile) throws FileNotFoundException, IOException {
  437.         if (getLiteralValue() != null && originalFile != null) {
  438.             if (!originalFile.exists()) {
  439.                 boolean createNewFile = originalFile.createNewFile();
  440.                 if (!createNewFile) {
  441.                     boolean delete = originalFile.delete();
  442.                     if (!delete) {
  443.                         throw new IOException("Unable to delete file: " + originalFile.getPath() + " could not be deleted, check the permissions of the file, directory, drive, and current user.");
  444.                     }
  445.                     createNewFile = originalFile.createNewFile();
  446.                     if (!createNewFile) {
  447.                         throw new IOException("Unable to create file: " + originalFile.getPath() + " could not be created, check the permissions of the file, directory, drive, and current user.");
  448.                     }
  449.                 }
  450.             }
  451.             if (originalFile.exists()) {
  452.                 try (BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(originalFile))) {
  453.                     output.write(getBytes());
  454.                     output.flush();
  455.                 }
  456.             } else {
  457.                 throw new FileNotFoundException("Unable Create File: the file \"" + originalFile.getAbsolutePath() + " could not be found or created.");
  458.             }
  459.         }
  460.     }

  461.     /**
  462.      * Returns the internal InputStream.
  463.      *
  464.      * <p>
  465.      * Remember to close the InputStream.
  466.      *
  467.      * <p style="color: #F90;">Support DBvolution at
  468.      * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
  469.      *
  470.      * @return an InputStream to read the bytes.
  471.      */
  472.     @Override
  473.     public InputStream getInputStream() {
  474.         return new BufferedInputStream(new ByteArrayInputStream(getBytes()));
  475.     }

  476.     /**
  477.      * Returns the byte[] used internally to store the value of this
  478.      * DBLargeBinary.
  479.      *
  480.      * <p style="color: #F90;">Support DBvolution at
  481.      * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
  482.      *
  483.      * @return the byte[] value of this DBLargeBinary.
  484.      */
  485.     public byte[] getBytes() {
  486.         final byte[] litVal = this.getLiteralValue();
  487.         if (litVal != null) {
  488.             return litVal;
  489.         }
  490.         return new byte[]{};
  491.     }

  492.     @Override
  493.     public String stringValue() {
  494.         byte[] value = this.getValue();
  495.         if (this.isNull()) {
  496.             return super.stringValue();
  497.         } else {
  498.             return new String(value, UTF_8);
  499.         }
  500.     }

  501.     @Override
  502.     public int getSize() {
  503.         final byte[] bytes = getBytes();
  504.         if (bytes != null) {
  505.             return bytes.length;
  506.         } else {
  507.             return 0;
  508.         }
  509.     }

  510.     @Override
  511.     public byte[] getValue() {
  512.         return getBytes();
  513.     }

  514.     @Override
  515.     public DBLargeBinary getQueryableDatatypeForExpressionValue() {
  516.         return new DBLargeBinary();
  517.     }

  518.     @Override
  519.     public boolean isAggregator() {
  520.         return false;
  521.     }

  522.     @Override
  523.     public Set<DBRow> getTablesInvolved() {
  524.         return new HashSet<>();
  525.     }

  526.     @Override
  527.     protected byte[] getFromResultSet(DBDefinition defn, ResultSet resultSet, String fullColumnName) throws SQLException {
  528.         byte[] bytes = new byte[]{};
  529.         LargeObjectHandlerType handler = defn.preferredLargeObjectReader(this);
  530.         switch (handler) {
  531.             case BLOB:
  532.                 bytes = getFromBLOB(resultSet, fullColumnName);
  533.                 break;
  534.             case BASE64:
  535.                 bytes = getFromBase64(resultSet, fullColumnName);
  536.                 break;
  537.             case BINARYSTREAM:
  538.                 bytes = getFromBinaryStream(resultSet, fullColumnName);
  539.                 break;
  540.             case CHARSTREAM:
  541.                 bytes = getFromCharacterReader(resultSet, fullColumnName);
  542.                 break;
  543.             case CLOB:
  544.                 bytes = getFromCLOB(resultSet, fullColumnName);
  545.                 break;
  546.             case STRING:
  547.                 bytes = getFromString(resultSet, fullColumnName);
  548.                 break;
  549.             case JAVAOBJECT:
  550.                 bytes = getFromJavaObject(resultSet, fullColumnName);
  551.                 break;
  552.             case BYTE:
  553.                 bytes = getFromGetBytes(resultSet, fullColumnName);
  554.                 break;
  555.         }
  556.         return bytes;
  557.     }

  558.     @Override
  559.     public boolean getIncludesNull() {
  560.         return false;
  561.     }

  562.     @Override
  563.     protected void setValueFromStandardStringEncoding(String encodedValue) {
  564.         throw new UnsupportedOperationException("DBLargeBinaryObject does not support setValueFromStandardStringEncoding(String) yet.");
  565.     }

  566.     private byte[] getFromBase64(ResultSet resultSet, String fullColumnName) {
  567.         throw new UnsupportedOperationException("DBLargeBinaryObject does not support getFromBase64(ResultSet, String) yet.");
  568.     }

  569.     private byte[] getFromString(ResultSet resultSet, String fullColumnName) {
  570.         throw new UnsupportedOperationException("DBLargeBinaryObject does not support getFromString(ResultSet,String) yet.");
  571.     }

  572.     private byte[] getFromJavaObject(ResultSet resultSet, String fullColumnName) {
  573.         throw new UnsupportedOperationException("DBLargeBinaryObject does not support getFromJavaObject(ResultSet, String) yet.");
  574.     }

  575.     @Override
  576.     public LargeBinaryColumn getColumn(RowDefinition row) throws IncorrectRowProviderInstanceSuppliedException {
  577.         return new LargeBinaryColumn(row, this);
  578.     }

  579.     /**
  580.      * Indicates whether object is NULL within the database
  581.      *
  582.      * <p>
  583.      * Databases and Java both use the term NULL but for slightly different
  584.      * meanings.
  585.      *
  586.      * <p>
  587.      * This method indicates whether the field represented by this object is NULL
  588.      * in the database sense.
  589.      *
  590.      * <p style="color: #F90;">Support DBvolution at
  591.      * <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
  592.      *
  593.      * @return TRUE if this object represents a NULL database value, otherwise
  594.      * FALSE
  595.      */
  596.     @Override
  597.     public boolean isNull() {
  598.         return super.isNull() && getLiteralValue() == null;//&& this.byteStream == null;
  599.     }

  600.     @Override
  601.     public synchronized DBLargeBinary copy() {
  602.         DBLargeBinary result = (DBLargeBinary) super.copy();
  603.         return result;
  604.     }

  605.     @Override
  606.     public Comparator<byte[]> getComparator() {
  607.         return new ByteArrayComparator();
  608.     }
  609. }