Ejemplo n.º 1
0
        /*
        ** Name: parseCall
        **
        ** Description:
        **	Populates a procedure information object with the info
        **	parsed from the request text.
        **
        **	The following Database Procedure call syntax is accepted:
        **
        **	{[? =] CALL [schema.]name[( params )]}
        **	EXECUTE PROCEDURE [schema.]name[( params )] [INTO ?]
        **	CALLPROC [schema.]name[( params )] [INTO ?]
        **
        **	params: param_spec | param_spec, params
        **	param_spec: [name =] [value]
        **	value: ? | numeric_literal | char_literal | hex_string |
        **		SESSION.table_name
        **
        **	Note that parameter values are optional and will be flagged
        **	as default parameters.  An empty parenthesis set implies a
        **	single default parameter.
        **
        ** Input:
        **	None.
        **
        ** Output:
        **	procInfo    Procedure information.
        **
        ** Returns:
        **	void.
        **
        ** History:
        **	13-Jun-00 (gordy)
        **	    Created.
        **	28-Mar-01 (gordy)
        **	    ProcInfo now parameter rather than return value as
        **	    info needed for constructing ProcInfo is not available.
        **      11-Jul-01 (loera01) SIR 105309
        **          Added support for Ingres syntax.
        **      27-Nov-01 (loera01)
        **          Added support for standard syntax for global temp table
        **          parameters.
        **	31-Oct-02 (gordy)
        **	    Moved procedure return value and global temp table parameter
        **	    parsing into this method.
        **	24-Feb-03 (gordy)
        **	    ProcInfo parameter index is now 0 based.  Permit named
        **	    parameters in escape syntax.
        */
        public void parseCall( ProcInfo procInfo )
        {
            int		token, index;
            String	name;

            /*
            ** By calling getQueryType() we verify that this is
            ** a procedure call request, determine if procedure
            ** return value is expected, and position the token
            ** scanner to read the procedure name (need to force
            ** type to UNKNOWN otherwise getQueryType() may not
            ** do the proper scanning).
            */
            query_type = UNKNOWN;
            getQueryType();

            if ( (query_type != QT_PROCEDURE  &&  query_type != QT_NATIVE_PROC)  ||
                nextToken( false ) != IDENT )
                throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );

            /*
            ** Save the procedure name, but check for schema qualification.
            */
            name = new String( text, token_beg, token_end - token_beg );
            token = nextToken( false );

            if ( token == P_PERIOD )
            {
                if ( nextToken( false ) != IDENT )
                    throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );

                procInfo.setSchema( name );
                name = new String( text, token_beg, token_end - token_beg );
                token = nextToken( false );
            }

            procInfo.setName( name );

            /*
            ** Process the optional parameter list.
            */
            if ( token == P_LPAREN )
            {
                for(
                    index = 0, token = nextToken( false );
                    token != EOF;
                    index++, token = nextToken( false )
                    )
                {
                    /*
                    ** Process next parameter value.
                    */
                    switch( token )
                    {
                        case P_RPAREN :	// End of parameter list.
                            procInfo.setParam( index, ProcInfo.PARAM_DEFAULT, null );
                            goto break_for_loop;		// We be done.

                        case P_COMMA :	// Missing parameter.
                            procInfo.setParam( index, ProcInfo.PARAM_DEFAULT, null );
                            goto continue_for_loop;	// Ready for next parameter.

                        case P_QMARK :	// Dynamic parameter marker
                            procInfo.setParam( index, ProcInfo.PARAM_DYNAMIC, null );
                            break;

                        case STRING :	// String parameter value.
                            procInfo.setParam( index, ProcInfo.PARAM_CHAR,
                                new String( text, token_beg + 1,
                                token_end - token_beg - 2 ) );	// skip quotes
                            break;

                        case P_PLUS :	// Numeric parameter value.
                        case P_MINUS :
                        case P_PERIOD :
                        case NUMBER :
                            try
                            {
                                int	type;
                                Object	value;
                                String	str;

                                type = parseNumeric( token_beg );
                                str = new String( text, token_beg,
                                    token_end - token_beg );
                                switch( type )
                                {
                                    case NUM_INT :
                                        type = ProcInfo.PARAM_INT;
                                        value = Int32.Parse( str );
                                        break;

                                    case NUM_DEC :
                                        type = ProcInfo.PARAM_DEC;
                                        value = Decimal.Parse( str );
                                        break;

                                    case NUM_FLT :
                                        type = ProcInfo.PARAM_FLOAT;
                                        value = Double.Parse( str );
                                        break;

                                    default :
                                        throw new FormatException();
                                }

                                procInfo.setParam( index, type, value );
                            }
                            catch( Exception )
                            {
                                throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
                            }
                            break;

                        case IDENT:
                            /*
                            ** This may be a Global Temp Table parameter, a hex
                            ** literal or parameter name.  The following token
                            ** differentiates between the three possibilities.
                            */
                            int prev_end = token_end;
                            int prev_beg = token_beg;

                        switch( nextToken( false ) )
                        {
                            case P_PERIOD :	// Global Temp Table?
                                if (
                                    keyword( text, prev_beg,
                                    prev_end, keywords ) == KW_SESSION  &&
                                    nextToken( false ) == IDENT
                                    )
                                    procInfo.setParam( index, ProcInfo.PARAM_SESSION,
                                        new String(text,token_beg,token_end - token_beg) );
                                else
                                    throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
                                break;

                            case STRING :	// Hex literal?
                                if (
                                    (prev_end - prev_beg) == 1  &&
                                    (text[ prev_beg ] == 'X' || text[ prev_beg ] == 'x')
                                    )
                                    procInfo.setParam( index, ProcInfo.PARAM_BYTE,
                                        hex2bin( text, token_beg + 1,
                                        token_end - token_beg - 2 ) );
                                else
                                    throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
                                break;

                            case P_EQUAL :	// Parameter name
                                procInfo.setParamName( index,
                                    new String( text, prev_beg, prev_end - prev_beg ) );

                                /*
                                ** The parameter value can be processed by
                                ** restarting at the top of the loop (but
                                ** need to avoid incrementing the index).
                                */
                                index--;
                                goto continue_for_loop;

                            default :
                                throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
                        }
                            break;

                        default:
                            throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
                    }

                    /*
                    ** A parameter has just been processed.  Either another
                    ** parameter follows, indicated by a separating comma,
                    ** or the end of the parameter list is expected (the
                    ** closing parenthesis).
                    */
                    if ( (token = nextToken( false )) == P_RPAREN )
                        break;
                    else  if ( token != P_COMMA )
                        throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
                continue_for_loop:
                    continue;
                }  // end for loop
            break_for_loop:

                /*
                ** We should be at the end of the parameter list.
                */
                if ( token == P_RPAREN )
                    token = nextToken( false );
                else
                    throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
            }

            /*
            ** Check syntax termination.  For the escape sequence this
            ** is just the closing brace: '}'.  For native Ingres, only the
            ** optional return value is expected: 'INTO ?'.
            */
            if ( query_type == QT_PROCEDURE )
            {
                if ( token != P_RBRACE  ||  nextToken( false ) != EOF )
                    throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
            }
            else  if ( token != EOF )
            {
                if (
                    token == IDENT  &&
                    keyword( text, token_beg, token_end, keywords ) == KW_INTO  &&
                    nextToken( false ) == P_QMARK  &&
                    nextToken( false ) == EOF
                    )
                    procedure_return = true;
                else
                    throw SqlEx.get( ERR_GC4014_CALL_SYNTAX );
            }

            procInfo.setReturn( procedure_return );
            return;
        }
Ejemplo n.º 2
0
			AdvanCall( DrvConn conn, String sql ) :
				// Initialize base class and override defaults.
					base(
						conn,
						DrvConst.TYPE_FORWARD_ONLY,
						DrvConst.DRV_CRSR_READONLY,
						DrvConst.CLOSE_CURSORS_AT_COMMIT )
		{
			title = trace.getTraceName() + "-CallableStatement[" + inst_id + "]";
			tr_id = "Call[" + inst_id + "]";

			/*
			** Flag all parameters as procedure parameters.
			*/
			paramSet.setDefaultFlags( ParamSet.PS_FLG_PROC_IN );
			bool native_proc = false;

			/*
			** Process the call procedure syntax.
			*/
			try
			{
				SqlParse parser = new SqlParse( sql, conn );
				procInfo = new ProcInfo( conn );
				parser.parseCall( procInfo );
				native_proc = (parser.getQueryType() == SqlParse.QT_NATIVE_PROC);
			}
			catch( SqlEx ex )
			{
				if ( trace.enabled() )  
					trace.log( title + ": error parsing query text" );
				if ( trace.enabled( 1 ) )  ex.trace( trace );
				throw ex;
			}

			/*
			** Count the number of dynamic parameters and allocate
			** the dynamic parameter mapping arrays. Clear the param
			** information if only default parameters.
			*/
			int	param_cnt = procInfo.getParamCount();
			int	dflt_cnt = 0;
			int	dynamic = 0; 

			for( int param = 0; param < param_cnt; param++ )
				switch( procInfo.getParamType( param ) )
				{
					case ProcInfo.PARAM_DYNAMIC :	dynamic++;	break;
					case ProcInfo.PARAM_DEFAULT :	dflt_cnt++;	break;
				}

			if ( param_cnt > 0 )  
				if ( param_cnt == dflt_cnt )
					procInfo.clearParams();	// No real parameters.
				else  if ( param_cnt != dynamic )
				{
					/*
					** Load meta-data parameter names to ensure
					** correct relationship between dynamic and
					** non-dynamic parameters.  See discussion
					** in class description for further details.
					*/
					if ( ! procInfo.paramNamesLoaded() )  procInfo.loadParamNames();
				}
    
    
			if ( procInfo.getReturn() )  
			{
				/*
				** The mapping arrays include an entry for the procedure 
				** result parameter to provide the correct offest for other 
				** parameters, but the entry can't be used for mapping.  
				*/
				dynamic++;

				/*
				** Native procedure syntax places the procedure result
				** parameter last.  Escape syntax places it first.
				*/
				procRsltIndex = (native_proc ? dynamic-1 : 0);
			}

			/*
			** The dynamic parameter map is used to map dynamic parameter 
			** ordinal indexes into internal parameter indexes.  Mapping
			** is required because the internal parameters include non-
			** dynamic parameters and the dynamic parameters may include
			** the procedure result.
			*/
			dpMap = (dynamic > 0) ? new int[ dynamic ] : noMap;
    
			/*
			** The output parameter map is used to map internal parameter
			** indexes (see above) into output result map indexes.  The
			** registered type/scale is saved in associated arrays (which
			** also provide space, in the last entry, for the procedure
			** result registration info).
			*/
			opMap = (param_cnt > 0) ? new int[ param_cnt ] : noMap;
			opType =  new ProviderType[ param_cnt + 1 ];	// Include procedure result
			opScale = new int[ param_cnt + 1 ];	// Include procedure result

			/*
			** Initialize the dynamic parameter mapping array 
			** and any static literal parameters.
			*/
			initParameters();
			return;
		} // AdvanCall