Esempio n. 1
0
        /*
        ** 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;
        }