Skip to content

Commit

Permalink
issue #1141
Browse files Browse the repository at this point in the history
The LOB opening and closing mechanism in Oracle has some restrictions which makes it implicitly usage is dangerous
This commit remove the call OCILobOpen from fetching and add some oracle blob tests
  • Loading branch information
Alexey Palienko committed Apr 15, 2024
1 parent 8a5ed87 commit 0c77f2e
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 2 deletions.
24 changes: 23 additions & 1 deletion src/backends/oracle/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,19 @@ void oracle_blob_backend::set_lob_locator(oracle_blob_backend::locator_t locator
}

initialized_ = initialized;
/*
* see https://docs.oracle.com/cd/A91202_01/901_doc/appdev.901/a89857/oci07lob.htm#436746
* The explicitly open/closing LOB technique is dangerous, as it can lead to errors.
* The LOB opening and closing mechanism has the following restrictions:
An application must close all previously opened LOBs before committing a transaction. Failing to do so will result in an error.
If a transaction is rolled back, all open LOBs are discarded along with the changes made (the LOBs are not closed), so associated triggers are not fired.
It is an error to open or close the same internal LOB twice within the same transaction, either with different locators or the same locator.
It is an error to close a LOB that has not been opened.
* TODO: This method should be used explicitly by the user
*
if (initialized)
{
boolean already_open = FALSE;
Expand All @@ -182,6 +194,7 @@ void oracle_blob_backend::set_lob_locator(oracle_blob_backend::locator_t locator
}
}
}
*/
}

void oracle_blob_backend::reset()
Expand All @@ -205,7 +218,16 @@ void oracle_blob_backend::reset()
}
else
{
res = OCILobClose(session_.svchp_, session_.errhp_, lobp_);
// https://docs.oracle.com/cd/A91202_01/901_doc/appdev.901/a89857/oci16ms8.htm#491367 An error is returned if the internal LOB is not open.
boolean is_open = FALSE;
res = OCILobIsOpen ( session_.svchp_, session_.errhp_, lobp_, &is_open );

if ( res != OCI_SUCCESS )
{
throw_oracle_soci_error ( res, session_.errhp_ );
}
if ( is_open )
res = OCILobClose(session_.svchp_, session_.errhp_, lobp_);
}

if (res != OCI_SUCCESS)
Expand Down
69 changes: 68 additions & 1 deletion tests/oracle/test-oracle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ struct basic_table_creator : public table_creator_base
}
};

TEST_CASE("Oracle nested statement", "[oracle][blob]")
TEST_CASE("Oracle nested statement", "[oracle][nested]")
{
soci::session sql(backEnd, connectString);
basic_table_creator tableCreator(sql);
Expand Down Expand Up @@ -1387,6 +1387,73 @@ TEST_CASE("Bulk iterators", "[oracle][bulkiters]")
sql << "drop table t";
}

struct blob_table_creator : public table_creator_base
{
blob_table_creator ( soci::session &sql ) : table_creator_base ( sql )
{
sql << "create table soci_test ("
" id number(10) not null,"
" img blob"
")";
}
};

TEST_CASE ( "Oracle blob", "[oracle][blob]" )
{
soci::session sql ( backEnd, connectString );

blob_table_creator tableCreator ( sql );

char buf[] = "abcdefghijklmnopqrstuvwxyz";
sql << "insert into soci_test (id, img) values (7, empty_blob())";

{
blob b ( sql );

oracle_session_backend *sessionBackEnd = static_cast<oracle_session_backend *> ( sql.get_backend () );

oracle_blob_backend *blobBackEnd = static_cast<oracle_blob_backend *> ( b.get_backend () );

sql << "select img from soci_test where id = 7", into ( b );
CHECK ( b.get_len () == 0 );

b.write_from_start ( buf, sizeof ( buf ) );
CHECK ( b.get_len () == sizeof ( buf ) );
b.trim ( 10 );
CHECK ( b.get_len () == 10 );
// append does not work (Oracle bug #886191 ?)
// b.append(buf, sizeof(buf));
// assert(b.get_len() == sizeof(buf) + 10);

}
sql.commit ();

{
blob b ( sql );
sql << "select img from soci_test where id = 7", into ( b );
// assert(b.get_len() == sizeof(buf) + 10);
CHECK ( b.get_len () == 10 );
char buf2[100];
b.read_from_start ( buf2, 10 );
CHECK ( strncmp ( buf2, "abcdefghij", 10 ) == 0 );
}

{
soci::statement stmt ( sql );
stmt.alloc ();
stmt.prepare ( "select img from soci_test where id = 7" );
row r;
stmt.exchange ( soci::into ( r ) );
stmt.define_and_bind ();
stmt.execute ();
stmt.fetch ();

auto b = r.move_as<blob> ( 0 );
CHECK ( b.get_len () == 10 );
}
}


//
// Support for soci Common Tests
//
Expand Down

0 comments on commit 0c77f2e

Please sign in to comment.