Multithreading and PreparedStatement

I am debugging a problem with the interaction between Hibernate and our JDBC driver.
Hibernate uses a PreparedStatement to insert values into the database. When it inserts a Timestamp value into the database, it sets the value into the Timestamp object, calls setTimestamp, and then it uses the same Timestamp object in other threads, setting it to different values, before it calls execute on the PreparedStatement.
My question is, is it valid for an application to assume that the JDBC driver has made a copy of the Timestamp value when it calls setTimestamp, or should it hold off on reusing the Timestamp value until after it has called execute?
To me it seems that the driver should be able to defer all processing of the PreparedStatement parameters until execute(), because the application could call clearParameters, in which case any work done by the JDBC driver would be wasted. This is not so obvious for Timestamp parameters, but what about stream parameters? Clearly the driver is not going to read the stream until execute.

I'm not talking about POJO. Think just straight JDBC, inside the guts of Hibernate.
Here is what Hibernate is doing:
Timestamp ts = new Timestamp();
// this one timestamp object is used by multiple threads
<now we have a thread that does this>
PreparedStatement pstmt = connection.prepareStatement("some sql");
ts.setTime(something);
pstmt.setTimestamp(n, ts);
<then, another thread does this:>
PreparedStatement pstmt1 = connection.prepareStatement("some sql");
ts.setTime(something else);
pstmt1.setTimestamp(n1, ts);
<meanwhile, the original thread is doing this>
pstmt.execute();
The JDBC driver only keeps a reference to the timestamp when Hibernate calls setTimestamp(). By the time Hibernate calls execute(), another thread has already picked up this timestamp object and reused it, so it doesn't contain the same value that it did when it called setTimestamp().
It's really horrible when the second thread calls setTime() when the first thread is in the execute() call, in the middle of reading its value to send it to the database, because the first thread reads an inconsistent value from the timstamp object and sends it to the database, which barfs because the inconsistent value ends up being something like Feb. 30. I can get this nightmare to happen pretty regularly on an SMP machine.
My question is: is Hibernate doing something bad by reusing the Timestamp object before calling execute(), or is the JDBC driver at fault for not keeping a copy of the Timestamp object at setTimestamp() time? I have read the JDBC spec over and over again and I can't see an answer to this question.

Similar Messages

  • Too many connections - even after closing ResultSets and PreparedStatements

    I'm getting a "Too many connections" error with MySQL when I run my Java program.
    2007-08-06 15:07:26,650 main/CLIRuntime [FATAL]: Too many connections
    com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: Too many connections
            at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:921)
            at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)
            at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:812)
            at com.mysql.jdbc.MysqlIO.secureAuth411(MysqlIO.java:3269)
            at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1182)
            at com.mysql.jdbc.Connection.createNewIO(Connection.java:2670)I researched on this and found out that I wasn't closing the ResultSet and the PreparedStatement.
    The JDBC connection is closed by a central program that handles connections (custom connection pooling).
    I added the code to close all ResultSets and PreparedStatements, and re-started MySQL as per the instructions here
    but still get "Too many connections" error.
    A few other things come to mind, as to what I may be doing wrong, so I have a few questions:
    1) A few PreparedStatements are created in one method, and they are used in a 2nd method and closed in the 2nd method
    does this cause "Too many connections" error?
    2) I have 2 different ResultSets, in nested while loops where the outer loop iterates over the first ResultSet and
    the inner loop iterates over the second ResultSet.
    I have a try-finally block that wraps the inner while loop, and I'm closing the second ResultSet and PreparedStement
    in the inner while loop.
    I also have a try-finally block that wraps the outer while loop, and I'm closing the first ResulSet and PreparedStatement
    in the outer while loop as soon as the inner while loop completes.
    So, in the above case the outer while loop's ResultSet and PreparedStatements remain open until the inner while loop completes.
    Does the above cause "Too many connections" error?
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The following is relevant sections of my code ( it is partially pseudo-code ) that shows the above 2 cases:
    init( Connection jdbcConnection ){
       String firstSQLStatement = "....";
       PreparedStatement ps1 = jdbcConnection.prepareStatement( firstSQLStatement );
       String secondSQLStatement = "....";
       PreparedStatement ps2 = jdbcConnection.prepareStatement( secondSQLStatement );
       String thirdSQLStatement = "....";
       PreparedStatement ps3 = null;
       ResultSet rsA = null;
       try{
            ps3 = jdbcConnection.prepareStatement( thirdSQLStatement );
            rsA = ps3.executeQuery();
            if( rsA.next() ){
                   rsA.getString( 1 );
       }finally{
            if( rsA != null )
                   rsA.close();
            if( ps3 != null )
              ps3.close();
       //Notice, how ps1 and ps2 are created here but not used immediately, but only ps3 is
       //used immediately.
       //ps1 and ps2 are used in another method.
    run( Connection jdbcConnection ){
         ResultSet rs1 = ps1.executeQuery();
            try{
               while(rs1.next()){
                    String s = rs1.getString();
                    ps2.setString(1, s);
              ResultSet rs2 = ps2.executeQuery();
                    try{
                   while(rs2.next()){
                        String s2 = rs2.getString();
                    }finally{
                   if( rs2 != null )
                     rs2.close();
                   if( ps2 != null )
                     ps2.close();
         }catch( Exception e ){
              e.printStackTrace();
         }finally{
            if( rs1 != null )
                  rs1.close();
               if( ps1 != null )
                  ps1.close();
    //Notice in the above case rs1 and ps1 are closed only after the inner
    //while loop completes.
    }I appreciate any help.

    Thanks for your reply.
    I will look at the central connection pooling mechanism ( which was written by someone else) , but that is being used by many other Java programs others have written.
    They are not getting this error.
    An addendum to my previous note, I followed the instructions here.
    http://dev.mysql.com/doc/refman/5.0/en/too-many-connections.html
    There's probably something else in my code that is not closing the connection.
    But I just wanted to rule out the fact that opening a PreparedStatement in one method and closing it in another is not a problem.
    Or, if nested ResultSet loops don't cause the problem.
    I've read in a few threads taht "Too many connections" can occur for unclosed RS and PS , and not just JDBC connections.

  • DataSource and PreparedStatement

    I am using DataSource and PreparedStatement in weblogic8.1 for a J2EE application.
    It works if we use only EJB..but if we use enterprise app. i.e. servlets,jsp,ejb etc.. it does not work.
    Can somebody tell the reason behind it??

    Why do you feel this is an issue with the PreparedStatements and not just the DataSource? Are you sure you have configured the DataSource correctly for your platforms outside your ejb container?

  • What is the different between statement and preparedstatement?

    hi,
    recently i have attended a telephonic interview. they asked me what is the different between statement and preparedstatement? and when u will use them? Hi! can any one say me the original difference??

    sorry dear,
    i am already shortlisted. and monday is my HR round.
    . Every 1 is not like u.
    So you have read the examples and explanations that you found when you googled, and you have read the javadoc and you still don't understand? And you are shortlisted? For what? I hope you won't do server programming.
    I will give you a few hints.
    Escaping of data
    Storing of dates
    Safer
    Faster

  • Performance Problem - MS SQL 2K and PreparedStatement

    Hi all
    I am using MS SQL 2k and used PreparedStatement to retrieve data. There is strange and serious performance problem when the PreparedStatement contains "?" and using PreparedStatement.setX() functions to set its value. I have performed the test with the following code.
    for (int i = 0; i < 10; i ++) {
    try {
    con = DBConnection.getInstance();
    statement = con.prepareStatement("SELECT * FROM cardno WHERE car_no = '" + cardNo + "'");
    // statement = con.prepareStatement("SELECT * FROM cardno WHERE car_no = ?");
    // statement.setString(1, cardNo);
    rs = statement.executeQuery();
    if (rs.next()) {
    catch(SQLException e) {
    e.printStackTrace();
    finally {
    try {
    rs.close();
    statement.close();
    catch(SQLException e) {
    e.printStackTrace();
    Iteration Time (ms)
    1 961
    10 1061
    200 1803
    for (int i = 0; i < 10; i ++) {
    try {
    con = DBConnection.getInstance();
    // statement = con.prepareStatement("SELECT * FROM cardno WHERE car_no = '" + cardNo + "'");
    statement = con.prepareStatement("SELECT * FROM cardno WHERE car_no = ?");
    statement.setString(1, cardNo);
    rs = statement.executeQuery();
    if (rs.next()) {
    catch(SQLException e) {
    e.printStackTrace();
    finally {
    try {
    rs.close();
    statement.close();
    catch(SQLException e) {
    e.printStackTrace();
    Iteration Time (ms)
    1 1171
    10 2754
    100 18817
    200 36443
    The above test is performed with DataDirect JDBC 3.0 driver. The one uses ? and setString functions take much longer to execute, which supposed to be faster because of precompilation of the statement.
    I have tried different drivers - the one provided by MS, data direct and Sprinta JDBC drivers but all suffer the same problem in different extent. So, I am wondering if MS SQL doesn't support for precompiled statement and no matter what JDBC driver I used I am still having the performance problem. If so, many O/R mappings cannot be used because I believe most of them if not all use the precompiled statement.
    Best regards
    Edmond

    Edmond,
    Most JDBC drivers for MS SQL (and I think this includes all the drivers you tested) use sp_executesql to execute PreparedStatements. This is a pretty good solution as the driver doesn't have to keep any information about the PreparedStatement locally, the server takes care of all the precompiling and caching. And if the statement isn't already precompiled, this is also taken care of transparently by SQL Server.
    The problem with this approach is that all names in the query must be fully qualified. This means that the driver has to parse the query you are submitting and make all names fully qualified (by prepending a db name and schema). This is why creating a PreparedStatement takes so much using these drivers (and why it does so every time you create it, even though it's the same PreparedStatement).
    However, the speed advantage of PreparedStatements only becomes visible if you reuse the statement a lot of times.
    As about why the PreparedStatement with no placeholder is much faster, I think is because of internal optimisations (maybe the statement is run as a plain statement (?) ).
    As a conclusion, if you can reuse the same PreparedStatement, then the performance hit is not so high. Just ignore it. However, if the PreparedStatement is created each time and only used a few times, then you might have a performance issue. In this case I would recommend you try out the jTDS driver ( http://jtds.sourceforge.net ), which uses a completely different approach: temporary stored procedures are created for PreparedStatements. This means that no parsing is done by the driver and PreparedStatement caching is possible (i.e. the next time you are preparing the same statement it will take much less as the previously submitted procedure will be reused).
    Alin.

  • Oracle, SELECT IN and PreparedStatement.setArray

    I want to execute the following query: SELECT * FROM SOMETABLE WHERE IDFIELD IN (?)
    The number of values in the IN list is variable. How can I do this with a prepared statement?
    I am aware of the different alternatives:
    1) Keep a cache of prepared statement for each sized list seen so far.
    2) Keep a cache of prepared statements for different sizes (1, 5, 10, 20) and fill in the left over parameter positions with the copies first value.
    They both have the disadvantage that there could be many prepared statements for each query that get used once, and never used again.
    I have tried this:
    stmt.execute ("CREATE OR REPLACE TYPE LONGINTLIST AS TABLE OF NUMBER(15)");
    ArrayDescriptor desc = ArrayDescriptor.createDescriptor ("LONGINTLIST", conn);
    long idValues [] = {2, 3, 4};
    oracle.sql.ARRAY paramArray = new oracle.sql.ARRAY (desc, conn, idValues);
    PreparedStatement query = conn.prepareStatement ("SELECT * FROM MYTABLE WHERE ID_FIELD IN (?)");
    query.setArray (1, paramArray);
    But Oracle gives a data conversion error.
    I then tried this:
    PreparedStatement query = conn.prepareStatement ("SELECT * FROM MYTABLE WHERE ID_FIELD IN (SELECT * FROM TABLE (?))");
    This works and the rows are returned, but the Oracle optimizer does not like it very much, since it always does a full table scan even though there is a primary key index on ID_FIELD.
    Any ideas?
    I also tried this:
    OraclePreparedStatement oraQuery = (OraclePreparedStatement) query;
    oraQuery.setARRAY (1, paramArray);
    But same behavior.
    Roger Hernandez

    Please re-read the original message. As I mentioned,
    I am aware of the two commonly used alternatives.No actually the most used alternative is to build the SQL dynamically each time.
    I know how to get both of them to work, and have used
    both alternatives in the past. The downside to both
    these approaches is that you need to save multiple
    prepared statements for each query. What I am trying
    to find is a way of having only one saved prepared
    statement for a query having a variable number of IN
    clause parameters.You could probably use a stored procedure that takes an 'array' and then do the processing in the stored proc to handle each array element.
    However, your database might not support that stored procs or arrays. Or it might not cache it with arrays. And the overhead of creating the array structure or processing it in the proc might eat any savings that you might gain (even presuming there is any savings) by using a prepared statement in the first place. Of course given that you must be using an automated profiling tool and have a loaded test environment you should be able to easily determine if this method saves time or not.
    Other than that there are no other solutions.

  • Statement and PreparedStatement which is better?

    There are two method to getting data from the database which is:
    1. Statement stmt=con.createStatement();
    rs=stmt.executeQuery("select name from table where id='"+X+"' and yr='"+ year +"'");
    2. PreparedStatement ps = con.prepareStatement("select name from table where id=? and yr=?);
    ps.setString(1, X);
    ps.setString(2, year);
    rs = ps.executeQuery();
    Both method can get the same result. However can anyone tell me that which method 's performance is better or the same? Under the condition that both statement are NOT used in a loop.

    Well the prepared statement does have another advantage: you don't have to think about the format of a date literal. When you put together the SQL for a normal Statement you must somehow create a date literal. With Oracle for example you need to make sure you either use it with the to_date() function or set the session date format beforehand, or rely on the setting of the server (you see: many pitfalls). And no, java.sql.Date does not handle that correctly. The same goes for Timestamp and probably numeric values as well (decimal point vs. decimal comma)
    If you use a PreparedStatement the driver handles this problem for you. So if you want your app to be portable across different DBMS I would go for a PreparedStatement.
    Thomas

  • Oracle 9i and PreparedStatement Date Problem

    Hi, I am working with Oracle 9i and it's version of the classes12.zip driver and I am having difficulties in storing a date value using a PreparedStatement. I only care about the date, but I have tried going the Timestamp route as well and get the same results.
    The PreparedStatement's parameters are being set successfully (using setDate or setTimestamp) but when the executeUpdate method is invoked, the process hangs. If I remove the Date (or Timestamp) from the insert, all works as expected.
    Has anyone else came across this problem and if so, how did you get around this?
    Thanks!
    -Brian

    That certainly hasn't happened with any other database including Oracle 8.
    Perhaps you might want to take another look at your code to make sure that it really isn't hanging but instead appears to do so when an exception occurs.

  • SetArray and PreparedStatement

    Is it possible to use setArray with a PreparedStatement (or setARRAY and OraclePreparedStatement, or anything else similar) to enable use of prepared statements in the situation where the query looks something like this:
    SELECT *
    FROM some_table
    WHERE some_field IN ( ? );
    where the number of elements in the set of the IN clause can vary on each execution?
    Hope I've explained myself properly.
    Thanks.

    I think you can.
    Refer to this document for more information on how to use it.
    http://download-west.oracle.com/docs/cd/B10501_01/java.920/a96654/oraarr.htm#1040124
    Regards,
    Anupama

  • Weblogic JTA timeout and PreparedStatement cache problem (Closed Statement)

    Hello,
    I am facing up a problem using a Weblogic connection pool with a PreparedStatement.
    Here is the environement :
    - Weblogic application server 10.3
    - JDBC connection pool with Oracle Thin driver (from server library) - all parameters by default i.e. StatementCache size = 10
    - JTA transaction timeout = 30s
    The problem is : if a prepared statement ends because of a JTA timeout, I receive the following stack exception/ stack trace
    java.sql.SQLException: The transaction is no longer active - status: 'Rolling Back. [Reason=weblogic.transaction.internal.TimedOutException: Transaction timed out after 33 seconds
    BEA1-000D8AE7230EFAA3EDC9]'. No further JDBC access is allowed within this transaction.
    at weblogic.jdbc.wrapper.JTSConnection.checkIfRolledBack(JTSConnection.java:178)
    at weblogic.jdbc.wrapper.JTSConnection.checkConnection(JTSConnection.java:188)
    at weblogic.jdbc.wrapper.Connection.preInvocationHandler(Connection.java:92)
    at weblogic.jdbc.wrapper.Connection.clearCachedStatement(Connection.java:814)
    at weblogic.jdbc.wrapper.PreparedStatement.clearCachedStatement(PreparedStatement.java:1357)
    and then, if we try to re-execute immediately the same operation (*same statement* but new request, new thread, new JTA transaction ...) we receive without delay the following exception :
    java.sql.SQLException: Closed Statement
    at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
    at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:112)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:173)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:229)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:403)
    It seems like a bug in the caching mechanism of Weblogic, the 1st stack trace shows method from the statement cache implementation, I presume weblogic is trying the clear the statement from the cache after the iniitial TimedOutException (SQLException), but as the JDBC connection is unusable at this point, the clearing fails and the statement remains in the cache but is physically closed by JDBC.
    1st question, why weblogic does need to call JTSConnection.checkConnection() for clearing a statement from its internal cache, it is a pure java memory operation isnt'it ?
    2nd question : How to solve the problem without setting the StatementCache size to 0 (I tried, it solves the problem)? I don't want to disable completely the Weblogic statement caching, I have a small PreparedStatement called very frequently.
    Thanks for any help

    The main issue is that the transactional context that is supposed to underlay the JDBC code being executed,
    has gone away. Indeed, any DBMS changes that may have been made by your code so far, have been rolled
    back and are gone. Your code should not be trying to continue JDBC as normal, and WebLogic is trying to stop
    you. The control flow should go back up to the location where the transaction was initiated, so as to restart from
    the beginning if that is what is desired, including getting a new JDBC connection and remaking all the statements
    etc.
    HTH,
    Joe
    Edited by: Joe Weinstein on Dec 3, 2010 9:12 AM

  • Multithreading and stored procedures

    Hi,
    Does anyone know of any problems with calling a stored procedure that returns a reference cursor in a multithreading application? In other words, if I have multiple threads calling the same stored procedure is the reference cursor guarenteed to be unique to each thread/thread safe?
    Thanks in advance,
    Glenn

    That should work fine and each call will get a separate ref cursor as long as the app is written properly and is managing it's threads anbd handles properly. Are you seeing some behaviour that suggests this is not the case?
    Chris

  • StringBuffer and PreparedStatement

    Does anyone know why prepared statements don't update ? fields when you provide the preparedstatement with a query that is a stringbuffer?
    i.e.
    StringBuffer query = new StringBuffer(500);
    query.append("SELECT * from Customer WHERE CustId = ?");
        try{
                          pstmt = conn.prepareStatement(
                               query.toString()
                    pstmt.setInt(1, 2);
                    result = pstmt.executeQuery();

    Why are you doing this?
    StringBuffer query = new StringBuffer(500);I am doing this before i have to dynmically manipulate the query, i have an array which i have to loop around and keep adding to the query till i get to the end. I cannot do this by simply specifiying the query inside the prepared statmenet paramaeter. The question mark parameters have nothing to do with adding to the query, it works fine if i specify the actual fields CustID = 1; instead of CustID = ?;
    SO my actual point was simply:
    I want to following query inside a string buffer where i can specifiy the paramaeters at a later stage using setInt, setString etc.
    SELECT * from Customer WHERE CustId = ?
    System.out.println(query.toString()); gives:
    SELECT * from Customer WHERE CustId = ?Now the string buffer, I'm specifiy the query reference directly to the preparedsttement i.e. this would be the same if i did conn.preparedStatment(SELECT * FROM CUSTOMER WHERE CustID = ?);
    try{
                          pstmt = conn.prepareStatement(
                               query.toString()
                     );After i use pstmt.setInt(1, 2);
    i get:
    SELECT * from Customer WHERE CustId = ?when it should be:
    SELECT * from Customer WHERE CustId = 2

  • MySql and PreparedStatement

    I am using WSAD 5.1 (Websphere Application Developer). My database is MySQL. I have set up a datasource that connects to MySQL in WSAD. I have a simple code that connects to the datasource using InitialContext.lookup.
    My Code :
    Connection conn = null;
    DataSource ds = null;
    try {
    InitialContext ctx = new InitialContext();
    ds = (DataSource)ctx.lookup("jdbc/ds1");     
    conn = ds.getConnection();
    } catch (NamingException e) {
    e.printStackTrace();
    //POINT 1
    PreparedStatement ps = conn.prepareStatement("select * from table1");
    ResultSet rs = ps.executeQuery( );
    rs.next();
    System.out.println("Value -> " + rs.getString(1));
    Error occurs at POINT 1. The error that im getting is this :
    java.sql.SQLException: Parameter with index of 1 is not set.
         at com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.enforceStatementProperties(WSJdbcPreparedStatement.java:426)
         at com.ibm.ws.rsadapter.jdbc.WSJdbcStatement.executeQuery(WSJdbcStatement.java:429)
    The weird thing is, if I use Statement instead of PreparedStatement, it works. I dont know whats wrong. Please, anyone, help.
    By the way, I need to use PreparedStatement, because im planning to use the same method with different queries, so some have "?" and some dont.
    Please.     

    If it's the same code and the same database then your configurations aren't the same on the various machines. Make the machine where it "fails" (whatever that means) be configured the same way as the other machines where it doesn't.
    You mentioned Websphere, so making sure the configurations are the same is going to be ridiculously difficult. But that's what you need to do.

  • DATE and PreparedStatement

    I'm trying to update a table using a PreparedStatement. Always receive the following SQL exception : ORA-01858: a non-numeric character was found where a numeric was expected. I send my date parameter has a string and try to convert them using the TO_CHAR/TO_DATE function.
    String psQuery = "update requ_ord set adj_horizon_date=? where ...";
    PreparedStatement pSt = conn.prepareStatement(psQuery);
    pSt.setString(1, "TO_DATE('2000-03-10', 'YYYY-MM-DD')");
    pSt.execute();
    null

    Hi,
    Your SQL statement is equivalent to
    update xxx set sdate='TO_date('2000-01-01','yyyy-mm-dd')'
    Above statement will give same error which you were getting..
    what you can do is change your sql statement to
    String psQuery = "update requ_ord set adj_horizon_date=to_date(?,'yyyy-mm-dd') where ...";
    Suresh
    null

  • What is the difference between Statement and PreparedStatement

    Hi
    What is the difference between Stement and PrepareStatement Other than PreCompilation and dynamic Parameters?
    Thanks in advance.
    Sekhar

    Most of the differences are either those, or consequences of those (such as better performance, greater security, and simpler use for PreparedStatement). Serious programmers should almost always use PreparedStatement.
    The only other thing I know of is trivial: you can get ResultSetMetaData from a PreparedStatement without actually executing a query.

Maybe you are looking for

  • Messages closes unexpectedly when trying to take and attach a photo within the application

    I have a tried and true iPhone 4S (yeah, I know) running iOS 8.0.2.  She's a tad slower than she used to be, but all in all seems to be working well with one exception.   When I try to take a photo from within the Messages application, the app crashe

  • Copy file between servers, passing on firewall

    I'm try copy a file between servers with Windows NT. I mapping the target server to drive X and test copying a file in windows explorer and command window and the files copy is OK. But if I try with a java class don't. I'm try with FileInputStream (r

  • Hardware/software requirements to support cable broadband

    I have a grape iMac G3 (333mhz)running OS 8.6 and am curious to know if this system, in it's current configuration is capable of supporting broadband via cable? Cox Communications is my cable provider and their stated minimum requirments lead me to b

  • Can we override an innerclass?

    Hi all, I like to know whether we can override an inner class?... I mean if class "A" has an inner class named "inner", and if class "B" extends Class "A", and if we provide a similar inner class named "inner" in the extended "B" class, then will the

  • Keywords from JPEG to DNG

    I have more than 3000 images that are keyworded using the JPEG file. I would like to transfer those keywords to the corresponding RAW file (actually RAW converted to DNG). As it stands, the only way I know of doing this is cutting and pasting the key