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 2 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
@@ -305,13 +305,12 @@ public long position(Blob pattern, long start)
* @param pos the position in the SQL <code>BLOB</code> value at which
* to start writing. The first position is <code>1</code>;
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.

When updating the javadoc to use @code, please update all instances for consistency

Copy link
Contributor Author

@kariya-mitsuru kariya-mitsuru May 24, 2021

Choose a reason for hiding this comment

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

Sure.

* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object.
* the length+1 of this {@code SerialBlob} object.
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.

Changes such as this require a CSR. I think I have convinced myself that it is OK to move forward with the CSR.

Copy link
Contributor Author

@kariya-mitsuru kariya-mitsuru May 24, 2021

Choose a reason for hiding this comment

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

Would you please create a CSR for me?
Or should I register a CSR at https://bugreport.java.com/bugreport/ ?

* @param bytes the array of bytes to be written to the <code>BLOB</code>
* value that this <code>Blob</code> 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>
* value from the database
@@ -327,27 +326,27 @@ public int setBytes(long pos, byte[] bytes)
* <code>BLOB</code> value that this <code>Blob</code> 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.
* 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.
* the length+1 of this {@code SerialBlob} object.
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* value
* @param offset the offset in the <code>byte</code> array at which
* to start reading the bytes. The first offset position is
* @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</code>; must not be less than <code>0</code> nor greater
* than the length of the <code>byte</code> array
* 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</code> 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;
* 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>
* value from the database.
@@ -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) {
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
@@ -368,15 +368,12 @@ public long position(Clob searchStr, long start)
* @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
* greater than the length+1 of this {@code SerialClob} object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>SerialClob</code> 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 {
@@ -391,7 +388,7 @@ public int setString(long pos, String str) throws SerialException {
* @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
* greater than the length+1 of this {@code SerialClob} 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
@@ -400,42 +397,50 @@ public int setString(long pos, String str) throws SerialException {
* @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;
* 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
// 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,66 @@ 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);
}
}
@@ -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
@@ -407,18 +407,21 @@ public void test31() throws Exception {

/*
* Check that setString() updates the appropriate characters in the
* SerialClob
* SerialClob (writePos - 1 + val1.length() - offset > sc.length() &&
* writePos - 1 + expectedWritten <= sc.length())
*/
@Test(enabled = false)
@Test
public void test32() throws Exception {
int writePos = 10;
int offset = 7;
int expectedWritten = 9;
String val = "Hi, I am Catwoman!!!!!!";
String val1 = "Hahaha the Joker, who are you?!";
String expected = "Hi, I am the Joker!";
String expected = "Hi, I am the Joker!!!!!";
SerialClob sc = new SerialClob(val.toCharArray());
int written = sc.setString(10, val1, 8, expectedWritten+1);
int written = sc.setString(writePos, val1, offset, expectedWritten);
assertEquals(written, expectedWritten);

assertEquals(sc.getSubString(1, (int) sc.length()), expected);
}

/*
@@ -496,4 +499,62 @@ public void test38() throws Exception {
SerialClob sc2 = serializeDeserializeObject(sc);
assertTrue(sc.equals(sc2), "SerialClobs not equal");
}

/*
* Check calling setString() with offset > val1.length() throws a
* SerialException
*/
@Test(expectedExceptions = SerialException.class)
public void test39() throws Exception {
String val1 = "hello";
int offset = val1.length() + 1;
SerialClob sc = new SerialClob(chars);
sc.setString(1, val1, offset, 0);
}

/*
* Check that setString() updates the appropriate characters in the
* SerialClob (writePos - 1 + expectedWritten > sc.length())
*/
@Test
public void test40() throws Exception {
int writePos = 13;
int offset = 7;
int expectedWritten = 24;
String val = "Hello, I am Bruce Wayne";
String val1 = "Hahaha the Joker, who are you?!";
String expected = "Hello, I am the Joker, who are you?!";
SerialClob sc = new SerialClob(val.toCharArray());
int written = sc.setString(writePos, val1, offset, expectedWritten);
assertEquals(written, expectedWritten);
assertEquals(sc.getSubString(1, (int) sc.length()), expected);
}

/*
* Check that setString() updates the appropriate characters in the
* SerialClob (writePos == sc.length() + 1)
*/
@Test
public void test41() throws Exception {
int writePos = 10;
int offset = 7;
int expectedWritten = 10;
String val = "Hi, I am ";
String val1 = "Hahaha the Joker!";
String expected = "Hi, I am the Joker!";
SerialClob sc = new SerialClob(val.toCharArray());
int written = sc.setString(writePos, val1, offset, expectedWritten);
assertEquals(written, expectedWritten);
assertEquals(sc.getSubString(1, (int) sc.length()), expected);
}

/*
* Validate a SerialException is thrown if length < 0 for setString
*/
@Test(expectedExceptions = SerialException.class)
public void test42() throws Exception {
int length = -1;
SerialClob sc = new SerialClob(chars);
int written = sc.setString(1, "hello", 1, length);
}
}