/* ** Name: exec ** ** Description: ** Send SQL statement to server and process results. ** A cursor is opened when executing a SELECT and a ** result-set is generated. Non-SELECT statements ** are simply executed and the row count is updated. ** ** Input: ** text Statement text. ** mode Execute mode: QUERY, UPDATE, UNKNOWN. ** ** Output: ** None. ** ** Returns: ** void. ** ** History: ** 26-Oct-99 (gordy) ** Extracted from interface methods. ** 15-Nov-99 (gordy) ** Pass max row count and column length to result set. ** 16-Nov-99 (gordy) ** Added query timeouts. ** 13-Dec-99 (gordy) ** Added fetch limit. ** 16-May-00 (gordy) ** Move SQL parsing back into individual query processing ** sections so that it occurs after parser.getCursonName(). ** 19-May-00 (gordy) ** If select loops have been enabled, and a cursor name has ** not been assigned, execute queries directly rather than ** opening a cursor. Locking had to be reorganized since ** select loops are not unlocked until the result set is ** closed. Also needed additional handling when executing ** (supposedly) non-queries and get a result set by mistake. ** 28-Mar-01 (gordy) ** Call result-set shut() to avoid top-level tracing. ** 20-Jun-01 (gordy) ** Pass cursor name to result-set according to spec: ** NULL if READONLY and not provided by application. ** 21-Jun-01 (gordy) ** Re-worked parsing to eliminate redundant code. Parser ** parameter replaced with simple query text string. Query ** parameter replaced with mode to convey caller intent. ** 20-Aug-01 (gordy) ** Use cursor type constants. Send READONLY flag to server. ** Warn if cursor mode changed to READONLY. ** 25-Oct-01 (gordy) ** Select loops are only supported at PROTO_2 and above. ** 31-Oct-01 (gordy) ** Timezone now passed to AdvanSQL. ** 31-Oct-02 (gordy) ** Adapted for generic GCF driver. ** 19-Feb-03 (gordy) ** Added method to calculate fetch size. ** 15-Apr-03 (gordy) ** Added connection timezones separate from date formatters. ** 7-Jul-03 (gordy) ** Added Ingres timezone config which affects date/time literals. ** 4-Aug-03 (gordy) ** Created neew result-set class for updatable cursors. ** 20-Aug-03 (gordy) ** Send AUTO_CLOSE flag for query statements. ** 12-Sep-03 (gordy) ** Timezone replaced by GMT indicator. ** 6-Oct-03 (gordy) ** Fetch first block of rows for select-loops and read-only cursors. ** 19-Jun-06 (gordy) ** I give up... GMT indicator replaced with connection. */ private void exec( String text, int mode ) { SqlParse parser = new SqlParse( text, conn ); int type = parser.getQueryType(); AdvanRSMD rsmd; String cursor = null; clearResults(); if ( mode == UNKNOWN ) mode = (type == SqlParse.QT_SELECT) ? QUERY : UPDATE; if ( type == SqlParse.QT_DELETE || type == SqlParse.QT_UPDATE ) cursor = parser.getCursorName(); msg.LockConnection(); try { String sql = parser.parseSQL( parse_escapes ); if ( mode == QUERY ) { int concurrency = getConcurrency( parser.getConcurrency() ); if ( conn.select_loops && crsr_name == null && concurrency != DrvConst.DRV_CRSR_UPDATE && conn.msg_protocol_level >= MSG_PROTO_2 ) { /* ** Select statement using a select loop. */ bool needEOG = true; msg.begin( MSG_QUERY ); msg.write( MSG_QRY_EXQ ); if ( conn.msg_protocol_level >= MSG_PROTO_3 ) { msg.write( MSG_QP_FLAGS ); msg.write( (short)4 ); msg.write( MSG_QF_FETCH_FIRST | MSG_QF_AUTO_CLOSE ); needEOG = false; } msg.write( MSG_QP_QTXT ); msg.write( sql ); msg.done( true ); if ( (rsmd = readResults( timeout, needEOG )) == null ) throw SqlEx.get( ERR_GC4017_NO_RESULT_SET ); resultSet = new RsltSlct( conn, this, rsmd, rslt_val_stmt, getPreFetchSize(), msg.moreMessages()); } else { /* ** Select statement using a cursor. Generate a ** cursor ID if not provided by the application. */ short flags = 0; bool needEOG = true; cursor = (crsr_name != null) ? crsr_name : conn.getUniqueID( crsr_prefix ); /* ** Parser removes FOR READONLY clause because it isn't ** a part of Ingres SELECT syntax. Tell server that ** cursor should be READONLY (kludge older protocol ** by restoring clause to query). */ if ( concurrency == DrvConst.DRV_CRSR_READONLY ) if ( conn.msg_protocol_level < MSG_PROTO_2 ) sql += " for readonly"; else if ( conn.msg_protocol_level < MSG_PROTO_3 ) flags |= MSG_QF_READONLY; else { flags |= MSG_QF_READONLY | MSG_QF_FETCH_FIRST; needEOG = false; } if ( conn.msg_protocol_level >= MSG_PROTO_3 ) flags |= MSG_QF_AUTO_CLOSE; msg.begin( MSG_QUERY ); msg.write( MSG_QRY_OCQ ); if ( flags != 0 ) { msg.write( MSG_QP_FLAGS ); msg.write( (short)2 ); msg.write( flags ); } msg.write( MSG_QP_CRSR_NAME ); msg.write( cursor ); msg.write( MSG_QP_QTXT ); msg.write( sql ); msg.done( true ); if ( (rsmd = readResults( timeout, needEOG )) == null ) throw SqlEx.get( ERR_GC4017_NO_RESULT_SET ); /* ** The cursor name is passed to the result-set ** for updatable cursors or if provided by the ** application (2.1 API spec). */ if ( (rslt_flags & MSG_RF_READ_ONLY) == 0 ) { resultSet = new RsltUpd( conn, this, rsmd, rslt_val_stmt, cursor ); if ( msg.moreMessages() ) readResults( timeout, needEOG ); } else { if ( rs_concur == DrvConst.DRV_CRSR_UPDATE ) setWarning( SqlEx.get( ERR_GC4016_RS_CHANGED ) ); resultSet = new RsltCurs( conn, this, rsmd, rslt_val_stmt, crsr_name, getPreFetchSize(), msg.moreMessages() ); } msg.UnlockConnection(); } } else if ( cursor != null ) { /* ** Positioned Delete/Update. */ msg.begin( MSG_QUERY ); msg.write( (type == SqlParse.QT_DELETE) ? MSG_QRY_CDEL : MSG_QRY_CUPD ); msg.write( MSG_QP_CRSR_NAME ); msg.write( cursor ); msg.write( MSG_QP_QTXT ); msg.write( sql ); msg.done( true ); if ( readResults( timeout, true ) != null ) // shouldn't happen throw SqlEx.get( ERR_GC4018_RESULT_SET_NOT_PERMITTED ); msg.UnlockConnection(); } else { /* ** Non-query statement. */ msg.begin( MSG_QUERY ); msg.write( MSG_QRY_EXQ ); msg.write( MSG_QP_QTXT ); msg.write( sql ); msg.done( true ); if ( (rsmd = readResults( timeout, true )) == null ) msg.UnlockConnection(); // We be done. else { /* ** Query unexpectedly returned a result-set. ** We need to cleanup the tuple stream and ** statement in the server. The easiest ** way to do this is go ahead and create a ** result-set and close it. */ resultSet = new RsltSlct( conn, this, rsmd, rslt_val_stmt, 1, false ); try { resultSet.shut(); } catch( SqlEx ) {} resultSet = null; throw SqlEx.get( ERR_GC4018_RESULT_SET_NOT_PERMITTED ); } } } catch( SqlEx ex ) { if ( trace.enabled() ) trace.log( title + ".execute(): error executing query" ); if ( trace.enabled( 1 ) ) ex.trace( trace ); msg.UnlockConnection(); throw ex; } return; }
/* ** Name: AdvanPrep ** ** Description: ** Class constructor. Primary constructor for this class ** and derived classes which prepare the SQL text. ** ** Input: ** conn Associated connection. ** query Query text. ** rs_type Default ResultSet type. ** rs_concur Cursor concurrency. ** rs_hold Default ResultSet holdability. ** ** Output: ** None. ** ** History: ** 19-May-99 (gordy) ** Created. ** 8-Sep-99 (gordy) ** Synchronize on DbConn. ** 29-Sep-99 (gordy) ** Use DbConn lock()/unlock() methods for ** synchronization to support BLOB streams. ** 26-Oct-99 (gordy) ** Implemented ODBC escape processing. ** 12-Nov-99 (gordy) ** Use configured date formatter. ** 17-Dec-99 (gordy) ** Check DBMS max varch length. ** 13-Jun-00 (gordy) ** Extracted functionality for derived classes to ** new protected constructor. ** 4-Oct-00 (gordy) ** Create unique ID for standardized internal tracing. ** 19-Oct-00 (gordy) ** Query prepare code extracted to prepare(). Process ** the query text then call new method to prepare query. ** 1-Nov-00 (gordy) ** Changed parameters for 2.0 extensions. ** 31-Oct-01 (gordy) ** Timezone now passed to AdvanSQL. ** 31-Oct-02 (gordy) ** Adapted for generic GCF driver. ** 19-Feb-03 (gordy) ** Added ResultSet holdability. ** 15-Apr-03 (gordy) ** Added connection timezones separate from date formatters. ** 7-Jul-03 (gordy) ** Added Ingres timezone config which affects date/time literals. ** 12-Sep-03 (gordy) ** Replaced timezones with GMT indicator and SqlDates utility. ** 1-Nov-03 (gordy) ** Save updatable table name. */ public AdvanPrep( DrvConn conn, String query, int rs_type, int rs_concur, int rs_hold ) : this(conn, rs_type, rs_concur, rs_hold) { title = trace.getTraceName() + "-PreparedStatement[" + inst_id + "]"; tr_id = "Prep[" + inst_id + "]"; if ( trace.enabled() ) trace.log( title + ": '" + query + "'" ); try { SqlParse sql = new SqlParse( query, conn ); query_text = sql.parseSQL( parse_escapes, parameterMarkers ); qry_concur = sql.getConcurrency(); } catch( SqlEx ex ) { if ( trace.enabled() ) trace.log( title + ": error parsing query text" ); if ( trace.enabled( 1 ) ) ex.trace( trace ); throw ex; } prepare(); return; }