Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8153490: Cannot setBytes() if incoming buffer's length is bigger than number of elements we want to insert. #4001

Closed
wants to merge 6 commits into from
Closed
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -298,22 +298,21 @@ public long position(Blob pattern, long start)
}

/**
* Writes the given array of bytes to the <code>BLOB</code> value that
* this <code>Blob</code> object represents, starting at position
* <code>pos</code>, and returns the number of bytes written.
* Writes the given array of bytes to the {@code BLOB} value that
* this {@code Blob} object represents, starting at position
* {@code pos}, and returns the number of bytes written.
*
* @param pos the position in the SQL <code>BLOB</code> value at which
* to start writing. The first position is <code>1</code>;
* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object.
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* value that this <code>Blob</code> object represents
* @param pos the position in the SQL {@code BLOB} value at which
* to start writing. The first position is {@code 1};
* must not be less than {@code 1} nor greater than
* the length+1 of this {@code SerialBlob} object.
* @param bytes the array of bytes to be written to the {@code BLOB}
* value that this {@code Blob} object represents
* @return the number of bytes written
* @throws SerialException if there is an error accessing the
* <code>BLOB</code> value; or if an invalid position is set; if an
* invalid offset value is set;
* {@code BLOB} value; or if an invalid position is set;
Copy link
Contributor

@LanceAndersen LanceAndersen May 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this addresses a typo, this will require a CSR

* if {@code free} had previously been called on this object
* @throws SQLException if there is an error accessing the <code>BLOB</code>
* @throws SQLException if there is an error accessing the {@code BLOB}
* value from the database
* @see #getBytes
*/
@@ -323,33 +322,33 @@ public int setBytes(long pos, byte[] bytes)
}

/**
* Writes all or part of the given <code>byte</code> array to the
* <code>BLOB</code> value that this <code>Blob</code> object represents
* Writes all or part of the given {@code byte} array to the
* {@code BLOB} value that this {@code Blob} object represents
* and returns the number of bytes written.
* Writing starts at position <code>pos</code> in the <code>BLOB</code>
* value; <i>len</i> bytes from the given byte array are written.
* Writing starts at position {@code pos} in the {@code BLOB}
* value; {@code length} bytes from the given byte array are written.
*
* @param pos the position in the <code>BLOB</code> object at which
* to start writing. The first position is <code>1</code>;
* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object.
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* @param pos the position in the {@code BLOB} object at which
* to start writing. The first position is {@code 1};
* must not be less than {@code 1} nor greater than
* the length+1 of this {@code SerialBlob} object.
* @param bytes the array of bytes to be written to the {@code BLOB}
* value
* @param offset the offset in the <code>byte</code> array at which
* to start reading the bytes. The first offset position is
* <code>0</code>; must not be less than <code>0</code> nor greater
* than the length of the <code>byte</code> array
* @param offset the offset into the array {@code bytes} at which
Copy link
Contributor

@LanceAndersen LanceAndersen Sep 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change all occurrences of {@code bytes} to {@code byte}s as this was caught as part of the CSR review.

Copy link
Contributor Author

@kariya-mitsuru kariya-mitsuru Oct 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for my very slow response.
These {@code bytes} point to the bytes argument, but should I change it to {@code byte}s?

Copy link
Contributor

@LanceAndersen LanceAndersen Oct 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for my very slow response.

No problem at all. I was delayed in getting the CSR created and finalized.

These {@code bytes} point to the bytes argument, but should I change it to {@code byte}s?
Yes please make that minor change. Thank you

* to start reading the bytes to be set. The first offset position is
* {@code 0}; must not be less than {@code 0} nor greater
* than the length of the array {@code bytes}
* @param length the number of bytes to be written to the
* <code>BLOB</code> value from the array of bytes <i>bytes</i>.
* {@code BLOB} value from the array of bytes {@code bytes}
*
* @return the number of bytes written
* @throws SerialException if there is an error accessing the
* <code>BLOB</code> value; if an invalid position is set; if an
* invalid offset value is set; if number of bytes to be written
* is greater than the <code>SerialBlob</code> length; or the combined
* values of the length and offset is greater than the Blob buffer;
* {@code BLOB} value; if an invalid position is set; if an
* invalid offset value is set; or the combined values of the
* {@code length} and {@code offset} is greater than the length of
* {@code bytes};
* if {@code free} had previously been called on this object
* @throws SQLException if there is an error accessing the <code>BLOB</code>
* @throws SQLException if there is an error accessing the {@code BLOB}
* value from the database.
* @see #getBytes
*/
@@ -361,26 +360,34 @@ public int setBytes(long pos, byte[] bytes, int offset, int length)
throw new SerialException("Invalid offset in byte array set");
}

if (pos < 1 || pos > this.length()) {
throw new SerialException("Invalid position in BLOB object set");
if (length < 0) {
throw new SerialException("Invalid arguments: length cannot be "
+ "negative");
}

if ((long)(length) > origLen) {
throw new SerialException("Buffer is not sufficient to hold the value");
if (pos < 1 || pos > len + 1) {
throw new SerialException("Invalid position in BLOB object set");
}

if ((length + offset) > bytes.length) {
if (length > bytes.length - offset) {
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
"and length that is greater that the Blob buffer");
"and length that is greater than the length of bytes");
}

if (pos - 1 + length > Integer.MAX_VALUE) {
throw new SerialException("Invalid length. Cannot have combined pos " +
"and length that is greater than Integer.MAX_VALUE");
}

int i = 0;
pos--; // correct to array indexing
while ( i < length || (offset + i +1) < (bytes.length-offset) ) {
this.buf[(int)pos + i] = bytes[offset + i ];
i++;
if (pos + length > len) {
len = pos + length;
byte[] newbuf = new byte[(int)len];
System.arraycopy(buf, 0, newbuf, 0, (int)pos);
buf = newbuf;
}
return i;
System.arraycopy(bytes, offset, buf, (int)pos, length);
return length;
}

/**
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -361,81 +361,86 @@ public long position(Clob searchStr, long start)
}

/**
* Writes the given Java <code>String</code> to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents, at the position
* <code>pos</code>.
* Writes the given Java {@code String} to the {@code CLOB}
* value that this {@code SerialClob} object represents, at the position
* {@code pos}.
*
* @param pos the position at which to start writing to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents; the first
* position is <code>1</code>; must not be less than <code>1</code> nor
* greater than the length of this <code>SerialClob</code> object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents
* @param pos the position at which to start writing to the {@code CLOB}
* value that this {@code SerialClob} object represents; the first
* position is {@code 1}; must not be less than {@code 1} nor
* greater than the length+1 of this {@code SerialClob} object
* @param str the string to be written to the {@code CLOB}
* value that this {@code SerialClob} object represents
* @return the number of characters written
* @throws SerialException if there is an error accessing the
* <code>CLOB</code> value; if an invalid position is set; if an
* invalid offset value is set; if number of bytes to be written
* is greater than the <code>SerialClob</code> length; or the combined
* values of the length and offset is greater than the Clob buffer;
* {@code CLOB} value; if an invalid position is set;
* if the {@code free} method had been previously called on this object
*/
public int setString(long pos, String str) throws SerialException {
return (setString(pos, str, 0, str.length()));
}

/**
* Writes <code>len</code> characters of <code>str</code>, starting
* at character <code>offset</code>, to the <code>CLOB</code> value
* that this <code>Clob</code> represents.
* Writes {@code len} characters of {@code str}, starting
* at character {@code offset}, to the {@code CLOB} value
* that this {@code Clob} represents.
*
* @param pos the position at which to start writing to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents; the first
* position is <code>1</code>; must not be less than <code>1</code> nor
* greater than the length of this <code>SerialClob</code> object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>Clob</code> object represents
* @param offset the offset into <code>str</code> to start reading
* @param pos the position at which to start writing to the {@code CLOB}
* value that this {@code SerialClob} object represents; the first
* position is {@code 1}; must not be less than {@code 1} nor
* greater than the length+1 of this {@code SerialClob} object
* @param str the string to be written to the {@code CLOB}
* value that this {@code Clob} object represents
* @param offset the offset into {@code str} to start reading
* the characters to be written
* @param length the number of characters to be written
* @return the number of characters written
* @throws SerialException if there is an error accessing the
* <code>CLOB</code> value; if an invalid position is set; if an
* invalid offset value is set; if number of bytes to be written
* is greater than the <code>SerialClob</code> length; or the combined
* values of the length and offset is greater than the Clob buffer;
* {@code CLOB} value; if an invalid position is set; if an
* invalid offset value is set; or the combined values of the
* {@code length} and {@code offset} is greater than the length of
* {@code str};
* if the {@code free} method had been previously called on this object
*/
public int setString(long pos, String str, int offset, int length)
throws SerialException {
isValid();
String temp = str.substring(offset);
char cPattern[] = temp.toCharArray();

if (offset < 0 || offset > str.length()) {
throw new SerialException("Invalid offset in byte array set");
throw new SerialException("Invalid offset in String object set");
}

if (pos < 1 || pos > this.length()) {
throw new SerialException("Invalid position in Clob object set");
if (length < 0) {
throw new SerialException("Invalid arguments: length cannot be "
+ "negative");
}

if ((long)(length) > origLen) {
throw new SerialException("Buffer is not sufficient to hold the value");
if (pos < 1 || pos > len + 1) {
throw new SerialException("Invalid position in Clob object set");
}

if ((length + offset) > str.length()) {
// need check to ensure length + offset !> bytes.length
if (length > str.length() - offset) {
// need check to ensure length + offset !> str.length
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
" and length that is greater that the Blob buffer");
" and length that is greater than the length of str");
}

if (pos - 1 + length > Integer.MAX_VALUE) {
throw new SerialException("Invalid length. Cannot have combined pos " +
"and length that is greater than Integer.MAX_VALUE");
}

int i = 0;
pos--; //values in the array are at position one less
while ( i < length || (offset + i +1) < (str.length() - offset ) ) {
this.buf[(int)pos + i ] = cPattern[offset + i ];
i++;
if (pos + length > len) {
len = pos + length;
char[] newbuf = new char[(int)len];
System.arraycopy(buf, 0, newbuf, 0, (int)pos);
buf = newbuf;
}
return i;

String temp = str.substring(offset, offset + length);
char cPattern[] = temp.toCharArray();
System.arraycopy(cPattern, 0, buf, (int)pos, length);
return length;
}

/**
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -396,4 +396,78 @@ public void test30() throws Exception {
long pos = sb.position(pattern, 2);
assertEquals(pos, expectedPos);
}

/*
* Validate that setBytes will properly write a set of bytes to the
* specified location in the SerialBlob and the correct count is returned
* for bytes written (writePos - 1 + diff.length > sb.length() &&
* writePos - 1 + bytesToWrite <= sb.length())
*/
@Test
public void test31() throws Exception {
int writePos = 5;
int bytesToWrite = 1;
byte[] diff = new byte[]{7, 8, 9};
byte[] expected = new byte[]{1, 2, 3, 4, 7};
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(writePos, diff, 0, bytesToWrite);
assertEquals(written, bytesToWrite);
assertEquals(sb.getBytes(1, (int) sb.length()), expected);
}

/*
* Validate that setBytes will properly write a set of bytes to the
* specified location in the SerialBlob and the correct count is returned
* for bytes written (writePos - 1 + bytesToWrite > sb.length())
*/
@Test
public void test32() throws Exception {
int writePos = 5;
int bytesToWrite = 2;
byte[] diff = new byte[]{7, 8, 9, 0};
byte[] expected = new byte[]{1, 2, 3, 4, 8, 9};
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(writePos, diff, 1, bytesToWrite);
assertEquals(written, bytesToWrite);
assertEquals(sb.getBytes(1, (int) sb.length()), expected);
}

/*
* Validate that setBytes will properly write a set of bytes to the
* specified location in the SerialBlob and the correct count is returned
* for bytes written (writePos == sb.length() + 1)
*/
@Test
public void test33() throws Exception {
int writePos = 6;
int bytesToWrite = 3;
byte[] diff = new byte[]{7, 8, 9, 0};
byte[] expected = new byte[]{1, 2, 3, 4, 5, 8, 9, 0};
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(writePos, diff, 1, bytesToWrite);
assertEquals(written, bytesToWrite);
assertEquals(sb.getBytes(1, (int) sb.length()), expected);
}

/*
* Validate a SerialException is thrown if length < 0 for setBytes
*/
@Test(expectedExceptions = SerialException.class)
public void test34() throws Exception {
int length = -1;
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(1, new byte[]{1}, 1, length);
}

/*
* Validate a SerialException is thrown if length + offset >
* Integer.MAX_VALUE for setBytes
*/
@Test(expectedExceptions = SerialException.class)
public void test35() throws Exception {
int offset = 1;
int length = Integer.MAX_VALUE;
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(1, new byte[]{1, 2, 3}, offset, length);
}
}