text: /** 
   *  Copyright (c) 1999~2017, Altibase Corp. and/or its affiliates. All rights reserved.
   *
   *  This program is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU Affero General Public License, version 3,
   *  as published by the Free Software Foundation.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   *  GNU Affero General Public License for more details.
   *
   *  You should have received a copy of the GNU Affero General Public License
   *  along with this program. If not, see <http://www.gnu.org/licenses/>.
   */
   
  
  /***********************************************************************
   * $id$
   **********************************************************************/
  
  #include <idl.h>
  #include <ide.h>
  
  #include <qci.h>
  #include <mt.h>
  
  #include <dkm.h>
  #include <dkiSession.h>
  
  #include <dkDef.h>
  #include <dkErrorCode.h>
  
  #include <dkifUtil.h>
  
  /*
   * DATE REMOTE_GET_COLUMN_VALUE_DATE ( dblink_name IN VARCHAR,
   *                                     statement_id IN BIGINT,
   *                                     column_idx IN INTEGER )
   *
   * Only this function is used in function or procedure.
   */
  
  extern mtdModule mtdVarchar;
  extern mtdModule mtdInteger;
  extern mtdModule mtdDate;
  extern mtdModule mtdBigint;
  
  static mtcName gFunctionName[1] =
  {
      { NULL, 28, (void *)"REMOTE_GET_COLUMN_VALUE_DATE" }
  };
  
  /*
   * Followings are dony by this function.
   *   Is in a function or a procedure body?
   *   Do type conversion
   *   Check parameters' value
   *   Extract parameters' value
   *   Call dkm interface for this main functionality.
   *   Prepare return value and set
   *
   * aStack[0] is return value ( DATE ).
   * aStack[1] is dblink_name.
   * aStack[2] is statement_id.
   * aStack[3] is column_idx
   */ 
  static IDE_RC dkifCalculateFunction( mtcNode * aNode,
                                       mtcStack * aStack,
                                       SInt aRemain,
                                       void * aInfo,
                                       mtcTemplate * aTemplate )
  {
      SChar sDblinkName[ DK_NAME_LEN + 1 ] = { };
      SLong sStatementId = 0;
      SInt sColumnIndex = 0;
      void * sQcStatement = NULL;
      dkiSession * sDkiSession = NULL;
      mtcColumn * sColumn = NULL;
      void * sValue = NULL;
      dkmSession * sSession = NULL;
      
      /* BUG-36527 */
      IDE_TEST_RAISE( aRemain < 4, ERR_STACK_OVERFLOW );
      
      IDE_TEST( qciMisc::getQcStatement( aTemplate, &sQcStatement )
                != IDE_SUCCESS );
      IDE_TEST_RAISE( sQcStatement == NULL, ERR_STATEMENT_IS_NULL );
      
      IDE_TEST( mtf::postfixCalculate( aNode,
                                       aStack,
                                       aRemain,
                                       aInfo,
                                       aTemplate )
                != IDE_SUCCESS );
  
      IDE_TEST( dkifUtilCheckNullColumn( aStack, 1 ) != IDE_SUCCESS );
      IDE_TEST( dkifUtilCheckNullColumn( aStack, 2 ) != IDE_SUCCESS );
      IDE_TEST( dkifUtilCheckNullColumn( aStack, 3 ) != IDE_SUCCESS );    
  
      IDE_TEST( dkifUtilCopyDblinkName( (mtdCharType *)aStack[1].value,
                                        sDblinkName )
                != IDE_SUCCESS );
  
      sStatementId = *( (mtdBigintType *)aStack[2].value );
  
      sColumnIndex = *( (mtdIntegerType *)aStack[3].value );
      
      IDE_TEST( qciMisc::getDatabaseLinkSession( sQcStatement,
                                                 (void **)&sDkiSession )
                != IDE_SUCCESS );
  
      sSession = dkiSessionGetDkmSession( sDkiSession );
      IDE_TEST( dkmCheckSessionAndStatus( sSession ) != IDE_SUCCESS );
      
      IDE_TEST( dkmCalculateGetColumnValue(
                    sQcStatement,
                    sSession,
                    sDblinkName,
                    sStatementId,
                    sColumnIndex,
                    &sColumn,
                    &sValue )
                != IDE_SUCCESS );
  
      /* BUG-36527 */
      IDE_TEST_RAISE( sColumn->module->id != MTD_DATE_ID, ERR_WRONG_TYPE );
  
      /*
       * return value
       */ 
      idlOS::memcpy( aStack[0].value,
                     sValue,
                     sColumn->module->actualSize( sColumn, sValue ) );
      
      return IDE_SUCCESS;
  
      IDE_EXCEPTION( ERR_STACK_OVERFLOW )
      {
          IDE_SET( ideSetErrorCode( mtERR_ABORT_STACK_OVERFLOW ) );        
      }
      IDE_EXCEPTION( ERR_STATEMENT_IS_NULL )
      {
          IDE_SET( ideSetErrorCode( dkERR_ABORT_DKI_STATEMENT_IS_NULL ) );
      }
      IDE_EXCEPTION( ERR_WRONG_TYPE )
      {
          IDE_SET( ideSetErrorCode( dkERR_ABORT_DK_MISMATCHED_COLUMN_TYPE ) );
      }
      IDE_EXCEPTION_END;
  
      IDE_ERRLOG( DK_TRC_LOG_ERROR );
      
      return IDE_FAILURE;
  }
  
  static const mtcExecute gFunctionExecute = {
      mtf::calculateNA,
      mtf::calculateNA,
      mtf::calculateNA,
      mtf::calculateNA,
      dkifCalculateFunction,
      NULL,
      mtx::calculateNA,
      mtk::estimateRangeNA,
      mtk::extractRangeNA
  };
  
  /*
   * Followings are done by this function.
   *   Check number of parameters
   *   Make type conversion for parameters
   *   Initialize return value's space(?)
   *   Register execute module
   */ 
  static IDE_RC dkifEstimateFunction( mtcNode * aNode,
                                      mtcTemplate * aTemplate,
                                      mtcStack * aStack,
                                      SInt /* aRemain */,
                                      mtcCallBack * aCallBack )
  {
      const mtdModule * sArgumentModules[] =
      {
          &mtdVarchar,
          &mtdBigint,
          &mtdInteger,        
      };
  
      const mtdModule* sReturnModule = &mtdDate;
      
      IDE_TEST( dkifUtilCheckNodeFlag( aNode->lflag, 3) != IDE_SUCCESS );
  
      IDE_TEST( mtf::makeConversionNodes( aNode,
                                          aNode->arguments,
                                          aTemplate,
                                          aStack + 1,
                                          aCallBack,
                                          sArgumentModules )
                != IDE_SUCCESS );
  
      aStack[0].column = aTemplate->rows[aNode->table].columns + aNode->column;
  
      IDE_TEST( mtc::initializeColumn( aStack[0].column,
                                       sReturnModule,
                                       0,
                                       0,
                                       0 )
                != IDE_SUCCESS );
  
      aTemplate->rows[aNode->table].execute[aNode->column] = gFunctionExecute;
  
      return IDE_SUCCESS;
      
      IDE_EXCEPTION_END;
  
      IDE_ERRLOG( DK_TRC_LOG_ERROR );
      
      return IDE_FAILURE;
      
  }
  
  /*
   * Function module.
   */ 
  mtfModule dkifRemoteGetColumnValueDate =
  {
      1 | MTC_NODE_OPERATOR_MISC | MTC_NODE_VARIABLE_TRUE,
      ~0,
      1.0,                    // default selectivity (비교 연산자 아님)
      gFunctionName,
      NULL,
      mtf::initializeDefault,
      mtf::finalizeDefault,
      dkifEstimateFunction
  };
  