II_EXTERN II_VOID II_FAR II_EXPORT IIapi_getDescriptor( IIAPI_GETDESCRPARM II_FAR *getDescrParm ) { IIAPI_HNDL *handle; IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_getDescriptor: retrieving columns from server\n" ); /* ** Validate Input parameters */ if ( ! getDescrParm ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_getDescriptor: null getDescriptor parameters\n" ); return; } getDescrParm->gd_genParm.gp_completed = FALSE; getDescrParm->gd_genParm.gp_status = IIAPI_ST_SUCCESS; getDescrParm->gd_genParm.gp_errorHandle = NULL; getDescrParm->gd_descriptorCount = 0; getDescrParm->gd_descriptor = NULL; handle = (IIAPI_HNDL *)getDescrParm->gd_stmtHandle; /* ** Make sure API is initialized */ if ( ! IIapi_initialized() ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_getDescriptor: API is not initialized\n" ); IIapi_appCallback( &getDescrParm->gd_genParm, NULL, IIAPI_ST_NOT_INITIALIZED ); return; } if ( ( ! IIapi_isStmtHndl( (IIAPI_STMTHNDL *)handle ) && ! IIapi_isDbevHndl( (IIAPI_DBEVHNDL *)handle ) ) || IIAPI_STALE_HANDLE( handle ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_getDescriptor: invalid handle\n" ); IIapi_appCallback( &getDescrParm->gd_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_getDescriptor: handle = %p\n", handle ); IIapi_clearAllErrors( handle ); IIapi_uiDispatch( IIAPI_EV_GETDESCR_FUNC, handle, (II_PTR)getDescrParm ); return; }
II_EXTERN II_VOID II_FAR II_EXPORT IIapi_getCopyMap( IIAPI_GETCOPYMAPPARM II_FAR *getCopyMapParm ) { IIAPI_STMTHNDL *stmtHndl; IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_getCopyMap: retrieving copy information from server\n" ); /* ** Validate Input parameters */ if ( ! getCopyMapParm ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_getCopyMap: null getCopyMap parameters\n" ); return; } getCopyMapParm->gm_genParm.gp_completed = FALSE; getCopyMapParm->gm_genParm.gp_status = IIAPI_ST_SUCCESS; getCopyMapParm->gm_genParm.gp_errorHandle = NULL; stmtHndl = (IIAPI_STMTHNDL *)getCopyMapParm->gm_stmtHandle; /* ** Make sure API is initialized */ if ( ! IIapi_initialized() ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_getCopyMap: API is not initialized\n" ); IIapi_appCallback( &getCopyMapParm->gm_genParm, NULL, IIAPI_ST_NOT_INITIALIZED ); return; } if ( ! IIapi_isStmtHndl( stmtHndl ) || IIAPI_STALE_HANDLE( stmtHndl ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_getCopyMap: invalid statement handle\n" ); IIapi_appCallback( &getCopyMapParm->gm_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_getCopyMap: stmtHndl = %p\n", stmtHndl ); IIapi_clearAllErrors( (IIAPI_HNDL *)stmtHndl ); IIapi_uiDispatch( IIAPI_EV_GETCOPYMAP_FUNC, (IIAPI_HNDL *)stmtHndl, (II_PTR)getCopyMapParm ); return; }
II_EXTERN II_VOID IIapi_appCallback ( IIAPI_GENPARM *genParm, IIAPI_HNDL *handle, IIAPI_STATUS status ) { IIAPI_STATUS err_status; if ( handle ) if ( ( err_status = IIapi_errorStatus( handle ) ) != IIAPI_ST_SUCCESS ) status = IIAPI_WORST_STATUS( status, err_status ); else { /* ** There are no errors on the handle, don't ** return an error handle to the application. */ handle = NULL; } genParm->gp_completed = TRUE; genParm->gp_status = status; genParm->gp_errorHandle = (II_PTR)handle; IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_appCallback: request completed, status = %s\n", IIAPI_PRINTSTATUS( status ) ); if ( handle ) { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "IIapi_appCallback: error handle %p\n", handle ); } if ( genParm->gp_callback ) { IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_appCallback: application callback\n" ); (*genParm->gp_callback)( genParm->gp_closure, (II_PTR)genParm ); } else if ( handle && handle->hd_delete ) { genParm->gp_errorHandle = (II_PTR)IIapi_saveErrors( handle ); } return; }
static char * ns_login( API_PARSE *parse, i4 buflen, char *buffer ) { char *user, *pwd, *value; i4 usrlen, pwdlen, len; STATUS status; if ( parse->opcode == API_KW_ADD ) { /* ** Password required and must be sent encrypted. */ user = ns_resolve_param( parse, API_FIELD_PARM, FALSE ); usrlen = STlength( user ); pwd = ns_resolve_param( parse, API_FIELD_PARM + 1, FALSE ); pwdlen = (STlength( pwd ) + 8) * 2; /* estimate encrypted length */ } else { /* ** Use GCN wild card format for password. */ user = ns_resolve_param( parse, API_FIELD_PARM, TRUE ); usrlen = STlength( user ); pwd = empty; pwdlen = 0; } /* Allow room for EOS and separating ',' */ len = usrlen + pwdlen + 2; /* ** Allocate storage for the final value ** and build it from the parameters ** retrieved above. */ value = (len <= buflen) ? buffer : (char *)MEreqmem( 0, len, FALSE, &status ); if ( ! value ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "ns_login: can't allocate value buffer\n" ); return( NULL ); } if ( parse->opcode != API_KW_ADD ) STpolycat( 3, user, ",", pwd, value ); else { /* ** Encrypt password directly into formatted output. */ STpolycat( 2, user, ",", value ); gcu_encode( user, pwd, &value[ usrlen + 1 ] ); } return( value ); }
static char * ns_value( API_PARSE *parse, i4 buflen, char *buffer ) { char *parms[ API_FIELD_MAX ]; char *value; i4 len, fld, fld_cnt; STATUS status; /* ** Get each (possibly optional) parameter ** and determine the size of the final ** combined value. */ fld_cnt = max( 0, parse->parms->parm_max - API_FIELD_PARM ); for( fld = len = 0; fld < fld_cnt; fld++ ) { parms[ fld ] = ns_resolve_param( parse, fld + API_FIELD_PARM, (parse->opcode != API_KW_ADD) ); len += STlength( parms[ fld ] ); } len += fld_cnt; /* Allow room for EOS and separating ',' */ if ( ! len ) len++; /* ** Use passed in buffer if large enough. ** Otherwise, allocate temp buffer. */ value = (len <= buflen) ? buffer : (char *)MEreqmem( 0, len, FALSE, &status ); if ( ! value ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "ns_value: can't allocate value buffer\n" ); return( NULL ); } /* ** Build the comma separated list of parameters. */ if ( fld_cnt ) STcopy( parms[ 0 ], value ); else *value = EOS; for( fld = 1; fld < fld_cnt; fld++ ) { STcat( value, "," ); STcat( value, parms[ fld ] ); } return( value ); }
II_EXTERN IIAPI_THREAD * IIapi_thread( II_VOID ) { IIAPI_THREAD *thread; STATUS status; i4 tid = PCtid(); IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "IIapi_thread(%d): retrieving local storage\n", tid ); status = MEtls_get( &IIapi_static->api_thread, (PTR *)&thread ); if ( status != OK ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_thread: error retrieving local storage: 0x%x\n", status ); return( NULL ); } if ( ! thread ) { thread = (IIAPI_THREAD *)MEreqmem( 0, sizeof( IIAPI_THREAD ), TRUE, &status ); if ( ! thread ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_thread: error allocating local storage 0x%x\n", status ); } else { IIAPI_TRACE( IIAPI_TR_INFO ) ("IIapi_thread(%d): allocated local storage %p\n",tid,thread); QUinit( &thread->api_op_q ); status = MEtls_set( &IIapi_static->api_thread, (PTR)thread ); if ( status != OK ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_thread: error saving local storage 0x%x\n", status ); MEfree( (PTR)thread ); thread = NULL; } } } IIAPI_TRACE( IIAPI_TR_DETAIL ) ( "IIapi_thread(%d): retrieved local storage %p\n", tid, thread ); return( thread ); }
II_EXTERN II_VOID II_FAR II_EXPORT IIapi_batch( IIAPI_BATCHPARM II_FAR *batchParm ) { IIAPI_CONNHNDL *connHndl; IIAPI_TRANHNDL *tranHndl; IIAPI_STMTHNDL *stmtHndl; IIAPI_HNDL *handle; IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_batch: adding a batch query\n" ); /* ** Validate Input parameters */ if ( ! batchParm ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: null batch parameters\n" ); return; } batchParm->ba_genParm.gp_completed = FALSE; batchParm->ba_genParm.gp_status = IIAPI_ST_SUCCESS; batchParm->ba_genParm.gp_errorHandle = NULL; connHndl = (IIAPI_CONNHNDL *)batchParm->ba_connHandle; handle = (IIAPI_HNDL *)batchParm->ba_tranHandle; stmtHndl = (IIAPI_STMTHNDL *)batchParm->ba_stmtHandle; /* ** Make sure API is initialized */ if ( ! IIapi_initialized() ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: API is not initialized\n" ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_NOT_INITIALIZED ); return; } /* ** Validate connection handle. */ if ( ! IIapi_isConnHndl( connHndl ) || IIAPI_STALE_HANDLE( connHndl ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: invalid connHndl %p\n", connHndl ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } /* ** Validate transaction handle. */ if ( handle && ! IIapi_isTranName( (IIAPI_TRANNAME *)handle ) && (! IIapi_isTranHndl( (IIAPI_TRANHNDL *)handle ) || IIAPI_STALE_HANDLE( handle )) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: invalid tranHndl %p\n", handle ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } /* ** Validate statement handle. */ if ( stmtHndl ) { if ( ! IIapi_isStmtHndl( (IIAPI_STMTHNDL *)stmtHndl ) || IIAPI_STALE_HANDLE( stmtHndl ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: invalid stmtHndl %p\n", stmtHndl ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } if ( ! handle || IIapi_isTranName( (IIAPI_TRANNAME *)handle) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: transaction handle required\n" ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } if ( handle != (IIAPI_HNDL *)stmtHndl->sh_tranHndl ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: wrong tranHndl %p for stmtHndl %p\n", handle, stmtHndl ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } if ( connHndl != IIapi_getConnHndl( (IIAPI_HNDL *)stmtHndl ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: wrong connHndl %p for stmtHndl %p\n", connHndl, stmtHndl ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } } IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_batch: connHndl = %p, tranHndl = %p, stmtHndl = %p, queryType = %d\n", batchParm->ba_connHandle, batchParm->ba_tranHandle, batchParm->ba_stmtHandle, batchParm->ba_queryType ); IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_batch: queryText = %s\n", batchParm->ba_queryText ? batchParm->ba_queryText : "<NULL>" ); IIapi_clearAllErrors( stmtHndl ? (IIAPI_HNDL *)stmtHndl : ( (handle && IIapi_isTranHndl( (IIAPI_TRANHNDL *)handle )) ? handle : (IIAPI_HNDL *)connHndl ) ); /* ** Check that batch processing is supported on the connection. */ if ( connHndl->ch_partnerProtocol < GCA_PROTOCOL_LEVEL_68 ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: batch not supported at protocol level %d\n", connHndl->ch_partnerProtocol ); if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, E_AP001F_BATCH_UNSUPPORTED, II_SS50008_UNSUPPORTED_STMT, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &batchParm->ba_genParm, (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE ); return; } /* ** Check restrictions on query type and associated info. */ if ( connHndl->ch_type != IIAPI_SMT_SQL || (batchParm->ba_queryType != IIAPI_QT_QUERY && batchParm->ba_queryType != IIAPI_QT_EXEC && batchParm->ba_queryType != IIAPI_QT_EXEC_PROCEDURE) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: invalid query type %d for connection type %d\n", batchParm->ba_queryType, connHndl->ch_type ); if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, E_AP0011_INVALID_PARAM_VALUE, II_SS50008_UNSUPPORTED_STMT, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &batchParm->ba_genParm, (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE ); return; } if ( batchParm->ba_queryType != IIAPI_QT_EXEC_PROCEDURE && ! batchParm->ba_queryText ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: query requires query text\n" ); if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, E_AP0011_INVALID_PARAM_VALUE, II_SS5000R_RUN_TIME_LOGICAL_ERROR, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &batchParm->ba_genParm, (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE ); return; } if ( batchParm->ba_queryType == IIAPI_QT_EXEC_PROCEDURE && ! batchParm->ba_parameters ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: query requires parameters, none indicated\n" ); if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, E_AP0011_INVALID_PARAM_VALUE, II_SS5000R_RUN_TIME_LOGICAL_ERROR, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &batchParm->ba_genParm, (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE ); return; } /* ** Allocate a transaction handle if one was not provided. */ if ( ! handle || IIapi_isTranName( (IIAPI_TRANNAME *)handle ) ) { /* ** Check to see if there is an active transaction. */ if ( ! IIapi_isQueEmpty( (QUEUE *)&connHndl->ch_tranHndlList ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ("IIapi_batch: connection has active transaction.\n"); if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, E_AP0003_ACTIVE_TRANSACTIONS, II_SS25000_INV_XACT_STATE, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &batchParm->ba_genParm, (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE ); return; } if ( ! ( tranHndl = IIapi_createTranHndl( (IIAPI_TRANNAME *)batchParm->ba_tranHandle, (IIAPI_CONNHNDL *)batchParm->ba_connHandle ) ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: createTranHndl failed\n" ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); return; } } else { /* ** Use existing transaction handle. */ tranHndl = (IIAPI_TRANHNDL *)handle; IIapi_clearAllErrors( (IIAPI_HNDL *)tranHndl ); } /* ** Allocate a new statement handle or initialize existing handle. */ if ( stmtHndl ) initStmtHndl( stmtHndl ); else if ( ! (stmtHndl = IIapi_createStmtHndl( connHndl, tranHndl )) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_batch: createStmtHndl failed\n" ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); goto freeTranHandle; } /* ** Update statement handle with batch query information. */ if ( batchParm->ba_queryText && ! (stmtHndl->sh_queryText = STalloc( batchParm->ba_queryText )) ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_batch: can't alloc query text\n" ); IIapi_appCallback( &batchParm->ba_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); goto freeStmtHandle; } stmtHndl->sh_queryType = batchParm->ba_queryType; if ( batchParm->ba_parameters ) stmtHndl->sh_flags |= IIAPI_SH_PARAMETERS; /* ** The current set of external batch/query flags ** are not applicable to batch processing, but ** we pass them along anyway. */ stmtHndl->sh_flags |= batchParm->ba_flags & IIAPI_QF_ALL_FLAGS; batchParm->ba_stmtHandle = (II_PTR)stmtHndl; batchParm->ba_tranHandle = (II_PTR)tranHndl; IIapi_uiDispatch( IIAPI_EV_BATCH_FUNC, (IIAPI_HNDL *)stmtHndl, (II_PTR)batchParm ); return; freeStmtHandle: /* ** If the statement handle is not the input handle, ** then we allocated a new handle above and we must ** now delete it. */ if ( stmtHndl != (IIAPI_STMTHNDL *)batchParm->ba_stmtHandle ) IIapi_deleteStmtHndl( stmtHndl ); freeTranHandle: /* ** If the transaction handle is not the input handle, ** then we allocated a new handle above and we must ** now delete it. */ if ( tranHndl != (IIAPI_TRANHNDL *)batchParm->ba_tranHandle ) IIapi_deleteTranHndl( tranHndl ); return; }
II_EXTERN IIAPI_ENVHNDL * IIapi_initAPI( II_LONG version, II_LONG timeout ) { IIAPI_ENVHNDL *envHndl; IIAPI_ENVHNDL *defEnvHndl; II_BOOL first_init = FALSE; STATUS status; char *env; if ( ! IIapi_static ) { /* ** Perform global initializations which are ** environment independent. */ first_init = TRUE; if ( ! ( IIapi_static = (IIAPI_STATIC *) MEreqmem( 0, sizeof( IIAPI_STATIC ), TRUE, &status ) ) ) return( NULL ); QUinit( &IIapi_static->api_env_q ); if ( MUi_semaphore( &IIapi_static->api_semaphore ) != OK ) goto muiFail; if ( MEtls_create( &IIapi_static->api_thread ) != OK ) goto metFail; /* ** Initialize sub-systems. */ IIAPI_INITTRACE(); IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_initAPI: initializing API.\n" ); /* ** Make sure II_SYSTEM or similar is set to provide useful feedback ** rather than just failing in one of following subsystems. */ NMgtAt( SYSTEM_LOCATION_VARIABLE, &env ); if ( env == NULL || *env == EOS ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_initAPI: error - %s not set.\n", SYSTEM_LOCATION_VARIABLE ); goto adfFail; } IIapi_init_mib(); if ( ! IIapi_initADF() ) goto adfFail; if ( ! IIapi_initGCA(timeout) ) goto gcaFail; /* Initialize the unicode collation values */ IIapi_static->api_unicol_init = FALSE; IIapi_static->api_ucode_ctbl = NULL; IIapi_static->api_ucode_cvtbl = NULL; /* ** Create the default environment. */ if ( ! (IIapi_static->api_env_default = (PTR)IIapi_createEnvHndl( IIAPI_VERSION_1 )) ) goto defFail; /* Spoken Language to use */ if( ( status = ERlangcode( (char *)NULL, &IIapi_static->api_slang ) != OK) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_initAPI: error initializing lang 0x%x\n", status ); return( NULL ); } /* ** The SQL state machines are used by default prior to ** IIapi_connect() being called, so make sure they are ** initialized. */ if ( IIapi_sm_init( IIAPI_SMT_SQL ) != IIAPI_ST_SUCCESS ) goto envFail; } /* ** Now do environment specific initialization. */ defEnvHndl = IIapi_defaultEnvHndl(); if ( version == IIAPI_VERSION_1 ) { /* ** Version 1 initializers share the default ** environment. Keep track of the number of ** initializers so that IIapi_termAPI() can ** determine when to do global shutdown. */ envHndl = defEnvHndl; MUp_semaphore( &defEnvHndl->en_semaphore ); defEnvHndl->en_initCount++; MUv_semaphore( &defEnvHndl->en_semaphore ); } else { /* ** Create a new environment for the initializer. ** These environments are saved on the global ** environment queue. The caller may also make ** API calls using the default environment handle, ** so increment the default environment handle ** initialization count. */ if ( (envHndl = IIapi_createEnvHndl( version )) ) { MUp_semaphore( &IIapi_static->api_semaphore ); QUinsert( (QUEUE *)envHndl, &IIapi_static->api_env_q ); MUv_semaphore( &IIapi_static->api_semaphore ); MUp_semaphore( &defEnvHndl->en_semaphore ); defEnvHndl->en_initCount++; MUv_semaphore( &defEnvHndl->en_semaphore ); } else { /* ** We may need to undo the global initialization. ** If not, the NULL environment handle will simply ** be returned. */ if ( first_init ) goto envFail; } } return( envHndl ); envFail: IIapi_deleteEnvHndl( (IIAPI_ENVHNDL *)IIapi_static->api_env_default ); defFail: IIapi_termGCA(); gcaFail: IIapi_termADF(); adfFail: IIAPI_TERMTRACE(); MEtls_destroy( &IIapi_static->api_thread, NULL ); metFail: MUr_semaphore( &IIapi_static->api_semaphore ); muiFail: MEfree( (PTR)IIapi_static ); IIapi_static = NULL; return( NULL ); }
II_EXTERN II_VOID II_FAR II_EXPORT IIapi_scroll( IIAPI_SCROLLPARM II_FAR *scrollParm ) { IIAPI_STMTHNDL *stmtHndl; IIAPI_CONNHNDL *connHndl; bool valid; IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_scroll: scroll cursor\n" ); /* ** Validate Input parameters */ if ( ! scrollParm ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_scroll: null scrollParms parameters\n" ); return; } scrollParm->sl_genParm.gp_completed = FALSE; scrollParm->sl_genParm.gp_status = IIAPI_ST_SUCCESS; scrollParm->sl_genParm.gp_errorHandle = NULL; stmtHndl = (IIAPI_STMTHNDL *)scrollParm->sl_stmtHandle; /* ** Make sure API is initialized */ if ( ! IIapi_initialized() ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_scroll: API is not initialized\n" ); IIapi_appCallback( &scrollParm->sl_genParm, NULL, IIAPI_ST_NOT_INITIALIZED ); return; } if ( ! IIapi_isStmtHndl( stmtHndl ) || IIAPI_STALE_HANDLE( stmtHndl ) || ! (connHndl = IIapi_getConnHndl( (IIAPI_HNDL *)stmtHndl)) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_scroll: invalid handle %p\n", stmtHndl ); IIapi_appCallback( &scrollParm->sl_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_scroll: handle = %p\n", stmtHndl ); IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_scroll: orientation = %d, offset = %d\n", scrollParm->sl_orientation, scrollParm->sl_offset ); IIapi_clearAllErrors( (IIAPI_HNDL *)stmtHndl ); /* ** Validate parameters. */ switch( scrollParm->sl_orientation ) { case IIAPI_SCROLL_NEXT : valid = TRUE; break; case IIAPI_SCROLL_BEFORE : case IIAPI_SCROLL_FIRST : case IIAPI_SCROLL_PRIOR : case IIAPI_SCROLL_CURRENT : case IIAPI_SCROLL_LAST : case IIAPI_SCROLL_AFTER : case IIAPI_SCROLL_ABSOLUTE : case IIAPI_SCROLL_RELATIVE : if ( connHndl->ch_partnerProtocol >= GCA_PROTOCOL_LEVEL_67 ) valid = TRUE; else { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_scroll: scrolling not supported\n" ); valid = FALSE; } break; default : IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_scroll: invalid orientation: %d\n", (II_LONG)scrollParm->sl_orientation ); valid = FALSE; break; } if ( ! valid ) { if ( ! IIapi_localError( (IIAPI_HNDL *)stmtHndl, E_AP0011_INVALID_PARAM_VALUE, II_SS22003_NUM_VAL_OUT_OF_RANGE, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &scrollParm->sl_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &scrollParm->sl_genParm, (IIAPI_HNDL *)stmtHndl, IIAPI_ST_FAILURE ); return; } IIapi_uiDispatch( IIAPI_EV_SCROLL_FUNC, (IIAPI_HNDL *)stmtHndl, (II_PTR)scrollParm ); return; }
II_EXTERN II_VOID IIapi_loadNSColumns ( IIAPI_STMTHNDL *stmtHndl, IIAPI_GETCOLPARM *getColParm, IIAPI_GCN_REQ_TUPLE *tuple ) { IIAPI_DESCRIPTOR *descr; IIAPI_DATAVALUE *value; API_PARSE *parse = (API_PARSE *)stmtHndl->sh_queryText; char buffer[ API_NS_MAX_LEN ]; char *str, *val[ 3 ]; u_i2 len; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "IIapi_loadNSColumns: %d columns starting at %d, %d total columns\n", (II_LONG)stmtHndl->sh_colFetch, (II_LONG)stmtHndl->sh_colIndex, (II_LONG)stmtHndl->sh_colCount ); /* ** Some columns are combined in the returned ** GCN value field. Break out the combinded ** columns for reference below. We don't ** expect to overflow the buffer, but just ** in case we truncate the input. */ if ( tuple->gcn_val.gcn_l_item > (sizeof( buffer ) - 1) ) tuple->gcn_val.gcn_value[ sizeof( buffer ) - 1 ] = EOS; gcu_words( tuple->gcn_val.gcn_value, buffer, val, ',', 3 ); descr = &stmtHndl->sh_colDescriptor[ stmtHndl->sh_colIndex ]; value = &getColParm->gc_columnData[ (getColParm->gc_rowsReturned * getColParm->gc_columnCount) + getColParm->gc_columnCount - stmtHndl->sh_colFetch ]; for( ; stmtHndl->sh_colFetch; stmtHndl->sh_colFetch--, stmtHndl->sh_colIndex++, descr++, value++ ) { /* ** Figure out which piece of of the tuple ** satisfies the current column depending ** on which object type is being accessed. */ switch( parse->object ) { case API_KW_NODE : switch( stmtHndl->sh_colIndex ) { case 0 : /* Type */ str = (parse->type == API_KW_GLOBAL) ? glob_type : priv_type; break; case 1 : /* Vnode */ str = tuple->gcn_obj.gcn_value; break; case 2 : /* Network address */ str = val[0]; break; case 3 : /* Protocol */ str = val[1]; break; case 4 : /* Listen address */ str = val[2]; break; } break; case API_KW_LOGIN : switch( stmtHndl->sh_colIndex ) { case 0 : /* Type */ str = (parse->type == API_KW_GLOBAL) ? glob_type : priv_type; break; case 1 : /* Vnode */ str = tuple->gcn_obj.gcn_value; break; case 2 : /* Login */ str = val[0]; break; } break; case API_KW_ATTR : switch( stmtHndl->sh_colIndex ) { case 0 : /* Type */ str = (parse->type == API_KW_GLOBAL) ? glob_type : priv_type; break; case 1 : /* Vnode */ str = tuple->gcn_obj.gcn_value; break; case 2 : /* Attribute Name */ str = val[0]; break; case 3 : /* Attribute Value */ str = val[1]; break; } break; case API_KW_SERVER : switch( stmtHndl->sh_colIndex ) { case 0 : /* Server type */ str = tuple->gcn_type.gcn_value; break; case 1 : /* Object */ str = tuple->gcn_obj.gcn_value; break; case 2 : /* Address */ str = val[0]; break; } break; } /* ** We should always get a valid string, ** but provide a default just in case. ** Strings are silently truncated if too ** long since we don't expect truncation ** to occur (except for the type column, ** in which case silent truncation is ** desired). */ if ( ! str ) str = err_str; len = STlength( str ); value->dv_null = FALSE; switch( descr->ds_dataType ) { case IIAPI_CHA_TYPE : len = min( len, descr->ds_length ); value->dv_length = len; MEcopy( (PTR)str, len, value->dv_value ); break; case IIAPI_VCH_TYPE : len = min( len, descr->ds_length - sizeof( len ) ); value->dv_length = sizeof( len ) + len; MEcopy( (PTR)&len, sizeof( len ), value->dv_value ); MEcopy( (PTR)str, len, (PTR)((char *)value->dv_value + sizeof( len )) ); break; default : /* ** Should not happen. */ value->dv_null = TRUE; value->dv_length = 0; break; } } return; }
II_EXTERN IIAPI_STATUS IIapi_parseNSQuery( IIAPI_STMTHNDL *stmtHndl, STATUS *func_status ) { API_PARSE *parse; i4 keyword[ API_FIELD_MAX ]; i4 fld, marker_index; STATUS status; *func_status = OK; /* ** Allocate the parse info structure. */ parse = (API_PARSE *)MEreqmem( 0, sizeof( API_PARSE ), TRUE, &status ); if ( ! parse ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_parseNSQuery: couldn't allocate parser info.\n" ); return( IIAPI_ST_OUT_OF_MEMORY ); } /* ** Tokenize the query text for individual ** field validation and processing. */ if ( (*func_status = ns_scanner( stmtHndl->sh_queryText, parse )) != OK ) { MEfree( (PTR)parse ); return( IIAPI_ST_FAILURE ); } /* ** Check for keywords and parameter markers in fields. */ for( fld = marker_index = 0; fld < parse->field_count; fld++ ) if ( fld >= ARRAY_SIZE( keyword_tbl ) ) ns_param_marker( parse, fld, &marker_index ); else { keyword[ fld ] = ns_keyword(parse->fields[fld], keyword_tbl[fld]); if ( keyword[ fld ] == INVALID_KEYWORD && ns_param_marker( parse, fld, &marker_index ) ) keyword[ fld ] = API_KW_PARAM; } if ( (*func_status = ns_validate( parse, keyword )) != OK ) { MEfree( (PTR)parse ); return( IIAPI_ST_FAILURE ); } /* ** Finally, we replace the original query ** text with our parsed information. */ MEfree( stmtHndl->sh_queryText ); stmtHndl->sh_queryText = (char *)parse; return( IIAPI_ST_SUCCESS ); }
static II_BOOL load_blob ( IIAPI_STMTHNDL *stmtHndl, IIAPI_GETCOLPARM *getColParm, IIAPI_DESCRIPTOR *descriptor, IIAPI_MSG_BUFF *msgBuff, IIAPI_DATAVALUE *dataValue ) { if ( ! (stmtHndl->sh_flags & IIAPI_SH_PURGE_SEGMENTS ) ) { /* ** Process the BLOB segments in the input buffer ** until we empty the input buffer, the end of ** the BLOB is reached, or we fill the output ** buffer. */ do { if ( ! cnvtBLOB2DataValue(stmtHndl,descriptor,msgBuff,dataValue) ) return( FALSE ); if ( ! (stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS) ) return( TRUE ); } while( dataValue->dv_length < descriptor->ds_length ); /* ** We have satisfied the request if this is the ** last column of a single row request. Other- ** wise we must purge the rest of the BLOB before ** processing the rest of the request. */ if ( stmtHndl->sh_colFetch <= 1 && getColParm->gc_rowCount <= 1 ) { /* ** There is a (very small) chance that we ** we filled the output buffer and read the ** last input segment at the same time. In ** this case the end-of-segments indicator ** has not been processed and may or may not ** be in the input buffer. ** ** Normally we would just return TRUE at this ** point, but the special case complicates ** things. If the end-of-segments indicator ** is in the input buffer, we want to process ** it so that the application can be told ** that this is the last segment. The check ** can be made by calling checkBLOBSegment(), ** but some special conditions must be handled. ** ** CheckBLOBSegment() requires the request to be ** complete and will change the column index if ** the end-of-segments indicator is processed. ** The result of all this is that we must do the ** work to finish the column processing and return ** FALSE so that the caller will not duplicate the ** work. */ stmtHndl->sh_colFetch--; checkBLOBSegment( stmtHndl, descriptor, msgBuff ); return( FALSE ); } stmtHndl->sh_flags |= IIAPI_SH_PURGE_SEGMENTS; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtBLOB2DataValue: begin purging segments\n" ); } /* ** Purge the input buffer of BLOB segments ** until we find the end of the blob or we ** empty the input buffer. */ while( stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS ) if ( ! cnvtBLOB2DataValue( stmtHndl, descriptor, msgBuff, dataValue ) ) return( FALSE ); /* ** We must be done with the BLOB. */ return( TRUE ); }
static IIAPI_SM_OUT * sm_evaluate ( IIAPI_EVENT event, IIAPI_STATE state, IIAPI_HNDL *ev_hndl, IIAPI_HNDL *sm_hndl, II_PTR parmBlock, IIAPI_SM_OUT *smo_buff ) { IIAPI_TRANHNDL *tranHndl = (IIAPI_TRANHNDL *)sm_hndl; IIAPI_SM_OUT *smo = NULL; SM_TRANSITION *smt; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "%s evaluate: evaluating event %s in state %s\n", sql_tran_sm.sm_id, IIAPI_PRINTEVENT( event ), IIAPI_PRINT_ID( state, SQL_TS_CNT, sql_ts_id ) ); /* ** Static evaluations depend solely on the current state and event. */ if ( (smt = smt_array[ event ][ state ]) ) { IIAPI_TRACE( IIAPI_TR_DETAIL ) ( "%s evaluate: static evaluation\n", sql_tran_sm.sm_id ); smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ smt->smt_action ], *smo ); smo->smo_next_state = smt->smt_next; } else /* Dynamic evaluations require additional predicates */ switch( event ) /* to determine the correct state transition. */ { /* ** Rollback requests may be for savepoints ** or the entire transaction. */ case IIAPI_EV_ROLLBACK_FUNC : if ( ((IIAPI_ROLLBACKPARM *)parmBlock)->rb_savePointHandle ) { /* ** Rollback to savepoint. */ switch( state ) { case SQL_TS_TRAN : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_12 ], *smo ); smo->smo_next_state = SQL_TS_RBSP; break; case SQL_TS_ABORT : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_21 ], *smo ); smo->smo_next_state = state; break; } } else { /* ** Rollback transaction. */ switch( state ) { case SQL_TS_IDLE : case SQL_TS_BEG : case SQL_TS_ABORT : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_10 ], *smo ); smo->smo_next_state = SQL_TS_IDLE; break; case SQL_TS_TRAN : case SQL_TS_PREP : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_13 ], *smo ); smo->smo_next_state = SQL_TS_ROLL; break; case SQL_TS_XA : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_13 ], *smo ); smo->smo_next_state = SQL_TS_XAEND; break; } } break; /* ** GCA_RESPONSE messages include the current DBMS ** transaction state, allowing detection of the ** start of a transaction and transaction aborts. ** In some cases, the query status is also of ** interest. */ case IIAPI_EV_RESPONSE_RCVD : { /* ** A fake GCA_RESPONSE message is generated for some cases ** of procedure execution. The GCA message buffer will be ** NULL in this case and it is assumed that the procedure ** executed successfully. ** ** The RESPONSE message is not consumed during evaluation. */ GCA_RE_DATA respData; if ( ! parmBlock || IIapi_readMsgResponse((IIAPI_MSG_BUFF *)parmBlock, &respData, FALSE) != IIAPI_ST_SUCCESS ) respData.gca_rqstatus = 0; if ( respData.gca_rqstatus & GCA_LOG_TERM_MASK ) { /* ** Transaction inactive (possibly aborted). */ switch( state ) { case SQL_TS_BEG : case SQL_TS_ABORT : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_0 ], *smo ); smo->smo_next_state = state; break; case SQL_TS_TRAN : case SQL_TS_XA : case SQL_TS_PREP : case SQL_TS_WSPR : case SQL_TS_WRSR : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_7 ], *smo ); smo->smo_next_state = SQL_TS_ABORT; break; } } else { /* ** Transaction active. */ switch( state ) { case SQL_TS_BEG : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_0 ], *smo ); smo->smo_next_state = SQL_TS_TRAN; break; case SQL_TS_TRAN : case SQL_TS_XA : case SQL_TS_PREP : case SQL_TS_ABORT : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_0 ], *smo ); smo->smo_next_state = state; break; case SQL_TS_WSPR : case SQL_TS_WRSR : smo = smo_buff; if ( respData.gca_rqstatus & GCA_FAIL_MASK ) STRUCT_ASSIGN_MACRO(sql_act_seq[SQL_TAS_9], *smo); else STRUCT_ASSIGN_MACRO(sql_act_seq[SQL_TAS_4], *smo); smo->smo_next_state = SQL_TS_TRAN; break; } } if ( respData.gca_rqstatus & GCA_FAIL_MASK ) { /* ** Request failed. */ switch( state ) { case SQL_TS_WONR : case SQL_TS_WOFR : smo = smo_buff; STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_18 ], *smo ); smo->smo_next_state = SQL_TS_IDLE; break; } } else { /* ** Request succedded. */ switch( state ) { case SQL_TS_WONR : smo = smo_buff; STRUCT_ASSIGN_MACRO(sql_act_seq[ SQL_TAS_4 ], *smo); smo->smo_next_state = SQL_TS_AUTO; break; case SQL_TS_WOFR : smo = smo_buff; STRUCT_ASSIGN_MACRO(sql_act_seq[ SQL_TAS_5 ], *smo); smo->smo_next_state = SQL_TS_IDLE; break; } } break; } /* ** GCA_REJECT messages should only occur in ** the connected state. They are processed ** by the connection SM. When significant, ** only handle when EOD. */ case IIAPI_EV_REJECT_RCVD : switch( state ) { case SQL_TS_CONN : { IIAPI_MSG_BUFF *msgBuff = (IIAPI_MSG_BUFF *)parmBlock; smo = smo_buff; if ( msgBuff->flags & IIAPI_MSG_EOD ) { STRUCT_ASSIGN_MACRO(sql_act_seq[ SQL_TAS_6 ], *smo); smo->smo_next_state = SQL_TS_IDLE; } else { smo->smo_action_cnt = 0; smo->smo_next_state = state; } break; } } break; /* ** GCA_RELEASE messages are mostly ignored. ** They are processed by the connection SM. ** When significant, only handle when EOD. */ case IIAPI_EV_RELEASE_RCVD : switch( state ) { case SQL_TS_IDLE : case SQL_TS_CONN : { IIAPI_MSG_BUFF *msgBuff = (IIAPI_MSG_BUFF *)parmBlock; smo = smo_buff; if ( msgBuff->flags & IIAPI_MSG_EOD ) { STRUCT_ASSIGN_MACRO(sql_act_seq[ SQL_TAS_6 ], *smo); smo->smo_next_state = SQL_TS_IDLE; } else { smo->smo_action_cnt = 0; smo->smo_next_state = state; } break; } default : /* ** Ignored in all other states. */ smo = smo_buff; smo->smo_next_state = state; smo->smo_action_cnt = 0; break; } break; /* ** The following events are ignored at the ** transaction level. They will be processed ** by the connection state machine. Since ** they are unconditionally ignored, it is ** easier to handle them here than maintaining ** static transitions for every state. */ case IIAPI_EV_ERROR_RCVD : case IIAPI_EV_EVENT_RCVD : case IIAPI_EV_NPINTERUPT_RCVD : case IIAPI_EV_TRACE_RCVD : case IIAPI_EV_PROMPT_RCVD : case IIAPI_EV_UNEXPECTED_RCVD : case IIAPI_EV_RESUME : case IIAPI_EV_RECV_ERROR : case IIAPI_EV_SEND_ERROR : smo = smo_buff; smo->smo_next_state = state; smo->smo_action_cnt = 0; break; } /* ** If a specific response was not generated above, ** produce a generalized error response. */ if ( ! smo ) { smo = smo_buff; if ( event <= IIAPI_EVENT_FUNC_MAX ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s Evaluate: API function called in wrong state\n", sql_tran_sm.sm_id ); STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_19 ], *smo ); smo->smo_next_state = state; } else if ( event <= IIAPI_EVENT_MSG_MAX ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s Evaluate: invalid message received\n", sql_tran_sm.sm_id ); STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_20 ], *smo ); smo->smo_next_state = state; } else { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s Evaluate: unexpected I/O completion\n", sql_tran_sm.sm_id ); STRUCT_ASSIGN_MACRO( sql_act_seq[ SQL_TAS_0 ], *smo ); smo->smo_next_state = state; } } /* ** If the input resulted in no state change ** and no actions to be executed, we can ** just ignore the event. */ if ( smo->smo_next_state == state && ! smo->smo_action_cnt ) { IIAPI_TRACE( IIAPI_TR_DETAIL ) ( "%s evaluate: nothing to do, transition ignored\n", sql_tran_sm.sm_id ); smo = NULL; } return( smo ); }
static II_BOOL sm_execute ( IIAPI_ACTION action, IIAPI_HNDL *ev_hndl, IIAPI_HNDL *sm_hndl, II_PTR parmBlock ) { IIAPI_TRANHNDL *tranHndl = (IIAPI_TRANHNDL *)sm_hndl; IIAPI_MSG_BUFF *msgBuff; IIAPI_STATUS status; II_BOOL success = TRUE; char queryText[ 64 ]; switch( action ) { case SQL_TA_REMC : /* ** Remember callback. */ tranHndl->th_callback = TRUE; tranHndl->th_parm = (IIAPI_GENPARM *)parmBlock; break; case SQL_TA_RECV : { /* ** Issue receive message request. */ IIAPI_MSG_BUFF *msgBuff = IIapi_allocMsgBuffer( sm_hndl ); if ( ! msgBuff ) status = IIAPI_ST_OUT_OF_MEMORY; else status = IIapi_rcvNormalGCA( sm_hndl, msgBuff, (II_LONG)(-1) ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; } case SQL_TA_SCOM : /* ** Format and send GCA_COMMIT message. */ if ( ! (msgBuff = IIapi_allocMsgBuffer( sm_hndl )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } msgBuff->msgType = GCA_COMMIT; msgBuff->flags = IIAPI_MSG_EOD; status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SRB : /* ** Format and send GCA_ROLLBACK message. */ if ( ! (msgBuff = IIapi_allocMsgBuffer( sm_hndl )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } msgBuff->msgType = GCA_ROLLBACK; msgBuff->flags = IIAPI_MSG_EOD; status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SSP : { /* ** Create savepoint handle. Format and ** send GCA_QUERY message 'savepoint <sp>'. */ IIAPI_SAVEPTHNDL *savePtHndl; IIAPI_SAVEPTPARM *savePtParm = (IIAPI_SAVEPTPARM *)parmBlock; if ( ! IIapi_createSavePtHndl( savePtParm ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } savePtHndl = savePtParm->sp_savePointHandle; STprintf( queryText, "savepoint %s\n", savePtHndl->sp_savePtName ); if ( ! (msgBuff = IIapi_createMsgQuery( sm_hndl, queryText )) ) { IIapi_deleteSavePtHndl( savePtHndl ); savePtParm->sp_savePointHandle = NULL; status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) { IIapi_deleteSavePtHndl( savePtHndl ); savePtParm->sp_savePointHandle = NULL; success = FALSE; } break; } case SQL_TA_SRBS : { /* ** Format and send GCA_QUERY message 'rollback to <savepoint>'. */ IIAPI_ROLLBACKPARM *rollParm = (IIAPI_ROLLBACKPARM *)parmBlock; IIAPI_SAVEPTHNDL *savePtHndl = rollParm->rb_savePointHandle; STprintf(queryText, "rollback to %s\n", savePtHndl->sp_savePtName); if ( ! (msgBuff = IIapi_createMsgQuery( sm_hndl, queryText )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; } case SQL_TA_SAON : /* ** Format and send GCA_QUERY message 'set autocommit on'. */ if ( ! (msgBuff = IIapi_createMsgQuery( sm_hndl, "set autocommit on" )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SAOF : /* ** Format and send GCA_QUERY message 'set autocommit off'. */ if ( ! (msgBuff = IIapi_createMsgQuery( sm_hndl, "set autocommit off" )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SSEC : /* ** Format and send GCA_SECURE message. */ if ( ! ( msgBuff = IIapi_createMsgSecure( tranHndl ) ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; case SQL_TA_SXAS : { /* ** Send XA Start message. */ IIAPI_XASTARTPARM *startParm = (IIAPI_XASTARTPARM *)parmBlock; if ( ! (msgBuff = IIapi_createMsgXA( sm_hndl, GCA_XA_START, &startParm->xs_tranID.ti_value.xaXID, startParm->xs_flags )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; } case SQL_TA_SXAE : { /* ** Send XA End message. */ IIAPI_XAENDPARM *endParm = (IIAPI_XAENDPARM *)parmBlock; if ( ! (msgBuff = IIapi_createMsgXA( sm_hndl, GCA_XA_END, &endParm->xe_tranID.ti_value.xaXID, endParm->xe_flags )) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } status = IIapi_sndGCA( sm_hndl, msgBuff, NULL ); if ( status != IIAPI_ST_SUCCESS ) success = FALSE; break; } case SQL_TA_PEND : /* ** Return transaction aborted to all pending operations. */ { IIAPI_STMTHNDL *stmtHndl; for( stmtHndl = (IIAPI_STMTHNDL *)tranHndl-> th_stmtHndlList.q_next; stmtHndl != (IIAPI_STMTHNDL *)&tranHndl->th_stmtHndlList; stmtHndl = (IIAPI_STMTHNDL *)stmtHndl-> sh_header.hd_id.hi_queue.q_next ) IIapi_abortStmtHndl( stmtHndl, E_AP0002_TRANSACTION_ABORTED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ); } break; case SQL_TA_DELH : /* ** Mark handle for deletion. */ QUremove( (QUEUE *)tranHndl ); sm_hndl->hd_delete = TRUE; /* ** If this was a distributed transaction, ** the associated distributed transaction ** name should be releasable during the ** callback. Since the transaction handle ** has not actually been deleted, it is ** still associated with the distributed ** transaction name. Normally, cases such ** as this are serialized by the dispatch ** operations queue, but IIapi_releaseXID() ** is not a dispatched request. So we need ** to drop the association prior to making ** the callback. */ if ( tranHndl->th_tranName ) { QUremove( &tranHndl->th_tranNameQue ); tranHndl->th_tranName = NULL; } break; case SQL_TA_DELX : /* ** Free associated transaction name handle. */ if ( tranHndl->th_tranName ) /* Should never be NULL */ { QUremove( &tranHndl->th_tranNameQue ); IIapi_deleteTranName( tranHndl->th_tranName ); tranHndl->th_tranName = NULL; } /* ** Mark handle for deletion. */ QUremove( (QUEUE *)tranHndl ); sm_hndl->hd_delete = TRUE; break; case SQL_TA_ERAB : /* ** Transaction Aborted. */ IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s: Transaction aborted\n", sql_tran_sm.sm_id ); if ( ! IIapi_localError( sm_hndl, E_AP0002_TRANSACTION_ABORTED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; } break; case SQL_TA_ERCF : /* ** Commit failed. */ IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s: transaction commit failed\n", sql_tran_sm.sm_id ); if ( ! IIapi_localError( sm_hndl, E_AP000B_COMMIT_FAILED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; } break; case SQL_TA_ERPC : /* ** Prepare-to-commit failed. */ IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s: transaction prepare failed\n", sql_tran_sm.sm_id ); if ( ! IIapi_localError( sm_hndl, E_AP000C_2PC_REFUSED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; } break; case SQL_TA_RRSP : { /* ** Read response message. */ IIAPI_MSG_BUFF *msgBuff = (IIAPI_MSG_BUFF *)parmBlock; GCA_RE_DATA respData; if ( (status = IIapi_readMsgResponse( msgBuff, &respData, TRUE )) != IIAPI_ST_SUCCESS ) { success = FALSE; break; } /* ** Check for XA error */ if ( respData.gca_rqstatus & GCA_XA_ERROR_MASK && respData.gca_errd5 && ! IIapi_xaError( sm_hndl, respData.gca_errd5 ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } break; } case SQL_TA_RXAR : { /* ** Read XA response message. */ IIAPI_MSG_BUFF *msgBuff = (IIAPI_MSG_BUFF *)parmBlock; GCA_RE_DATA respData; if ( (status = IIapi_readMsgResponse( msgBuff, &respData, TRUE )) != IIAPI_ST_SUCCESS ) { success = FALSE; break; } /* ** If no XA error is returned, generate generic XA error. */ if ( ! (respData.gca_rqstatus & GCA_XA_ERROR_MASK) || ! respData.gca_errd5 ) respData.gca_errd5 = IIAPI_XAER_RMERR; if ( ! IIapi_xaError( sm_hndl, respData.gca_errd5 ) ) { status = IIAPI_ST_OUT_OF_MEMORY; success = FALSE; break; } break; } case SQL_TA_CBOK : /* ** Callback with success. Note that ** this will pick up the most severe ** status from the errors associated ** with the event handle. */ if ( tranHndl->th_callback ) { IIapi_appCallback(tranHndl->th_parm, sm_hndl, IIAPI_ST_SUCCESS); tranHndl->th_callback = FALSE; } break; case SQL_TA_CBFL : /* ** Callback with failure. */ if ( tranHndl->th_callback ) { IIapi_appCallback(tranHndl->th_parm, sm_hndl, IIAPI_ST_FAILURE); tranHndl->th_callback = FALSE; } break; case SQL_TA_CBIF : /* ** API function called in wrong state. */ if ( ! IIapi_localError( sm_hndl, E_AP0006_INVALID_SEQUENCE, II_SS5000R_RUN_TIME_LOGICAL_ERROR, IIAPI_ST_FAILURE ) ) status = IIAPI_ST_OUT_OF_MEMORY; else status = IIAPI_ST_FAILURE; /* ** This may not have been a transaction ** related function, and we may have a ** callback saved on the transaction ** handle, so we carefully make the ** callback to the caller making sure ** not to disturb the transaction handle. */ IIapi_appCallback( (IIAPI_GENPARM *)parmBlock, sm_hndl, status ); break; case SQL_TA_CBAB : /* ** Callback with transaction abort. */ if ( tranHndl->th_callback ) { if ( ! IIapi_localError( sm_hndl, E_AP0002_TRANSACTION_ABORTED, II_SS40001_SERIALIZATION_FAIL, IIAPI_ST_FAILURE ) ) status = IIAPI_ST_OUT_OF_MEMORY; else status = IIAPI_ST_FAILURE; IIapi_appCallback( tranHndl->th_parm, sm_hndl, status ); tranHndl->th_callback = FALSE; } break; case SQL_TA_CBABX : /* ** Callback with XA transaction abort. */ if ( tranHndl->th_callback ) { if ( ! IIapi_xaError( sm_hndl, IIAPI_XA_RBROLLBACK ) ) status = IIAPI_ST_OUT_OF_MEMORY; else status = IIAPI_ST_FAILURE; IIapi_appCallback( tranHndl->th_parm, sm_hndl, status ); tranHndl->th_callback = FALSE; } break; case SQL_TA_RCVE : /* ** Receive error. ** ** We have received an invalid message. ** Since the connection state machine ** may ignore this particular message ** type, convert to a type which will ** ensure the proper handling in all ** state machines. */ IIapi_liDispatch( IIAPI_EV_UNEXPECTED_RCVD, sm_hndl, NULL, NULL ); break; case SQL_TA_HALT : /* ** Halt state machine execution. */ return( FALSE ); } /* ** If we couldn't complete the action, callback with failure. */ if ( ! success && tranHndl->th_callback ) { IIapi_appCallback( tranHndl->th_parm, sm_hndl, status ); tranHndl->th_callback = FALSE; } return( success ); }
static IIAPI_SM_OUT * sm_evaluate ( IIAPI_EVENT event, IIAPI_STATE state, IIAPI_HNDL *ev_hndl, IIAPI_HNDL *sm_hndl, II_PTR parmBlock, IIAPI_SM_OUT *smo_buff ) { IIAPI_TRANHNDL *tranHndl = (IIAPI_TRANHNDL *)sm_hndl; IIAPI_SM_OUT *smo = NULL; SM_TRANSITION *smt; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "%s evaluate: evaluating event %s in state %s\n", ns_tran_sm.sm_id, IIAPI_PRINTEVENT( event ), IIAPI_PRINT_ID( state, NS_TS_CNT, ns_ts_id ) ); /* ** Static evaluations depend solely on the current state and event. */ if ( (smt = smt_array[ event ][ state ]) ) { IIAPI_TRACE( IIAPI_TR_DETAIL ) ( "%s evaluate: static evaluation\n", ns_tran_sm.sm_id ); smo = smo_buff; STRUCT_ASSIGN_MACRO( ns_act_seq[ smt->smt_action ], *smo ); smo->smo_next_state = smt->smt_next; } /* ** If a specific response was not generated above, ** produce a generalized error response. */ if ( ! smo ) { smo = smo_buff; if ( event <= IIAPI_EVENT_FUNC_MAX ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s Evaluate: API function called in wrong state\n", ns_tran_sm.sm_id ); STRUCT_ASSIGN_MACRO( ns_act_seq[ NS_TAS_3 ], *smo ); smo->smo_next_state = state; } else if ( event <= IIAPI_EVENT_MSG_MAX ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s Evaluate: invalid message received\n", ns_tran_sm.sm_id ); STRUCT_ASSIGN_MACRO( ns_act_seq[ NS_TAS_4 ], *smo ); smo->smo_next_state = state; } else { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "%s Evaluate: unexpected I/O completion\n", ns_tran_sm.sm_id ); STRUCT_ASSIGN_MACRO( ns_act_seq[ NS_TAS_0 ], *smo ); smo->smo_next_state = state; } } /* ** If the input resulted in no state change ** and no actions to be executed, we can ** just ignore the event. */ if ( smo->smo_next_state == state && ! smo->smo_action_cnt ) { IIAPI_TRACE( IIAPI_TR_DETAIL ) ( "%s evaluate: nothing to do, transition ignored\n", ns_tran_sm.sm_id ); smo = NULL; } return( smo ); }
II_EXTERN IIAPI_MSG_BUFF * IIapi_createGCNOper( IIAPI_STMTHNDL *stmtHndl ) { IIAPI_MSG_BUFF *msgBuff; u_i1 *msg; char *str, temp[ 512 ]; i4 val; IIAPI_CONNHNDL *connHndl = IIapi_getConnHndl((IIAPI_HNDL *)stmtHndl); API_PARSE *parse = (API_PARSE *)stmtHndl->sh_queryText; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "IIapi_createGCNOper: creating GCN Oper message\n" ); if ( ! connHndl ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_createGCNOper: can't get connHndl from stmtHnd\n" ); return( NULL ); } if ( ! (msgBuff = IIapi_allocMsgBuffer( (IIAPI_HNDL *)connHndl )) ) return( NULL ); msgBuff->msgType = GCN_NS_OPER; msg = msgBuff->data + msgBuff->length; /* ** Set the operations flags. ** ** Netutil always sets the merge flag when adding ** nodes, so we will too. ** ** The user ID flag is set if a username was given ** for IIapi_connect() but no password. The Name ** Server will reject the request if current user ** not authorized. ** ** The public flag is set for global values. ** ** The network database flag is set for non-server ** requests. ** ** We currently don't support the sole server flag. ** The merge flag is only marginally supported. ** These flags are mostly used for adding servers, ** which is currently only supported as an ** undocumented feature. */ val = GCN_DEF_FLAG; /* gcn_flag */ if ( parse->opcode == API_KW_ADD && ( parse->object == API_KW_NODE || parse->object == API_KW_ATTR ) ) val |= GCN_MRG_FLAG; if ( connHndl->ch_username && ! connHndl->ch_password ) val |= GCN_UID_FLAG; if ( parse->type == API_KW_GLOBAL ) val |= GCN_PUB_FLAG; if ( parse->object != API_KW_SERVER ) val |= GCN_NET_FLAG; I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); switch( parse->opcode ) /* gcn_opcode */ { case API_KW_ADD : val = GCN_ADD; break; case API_KW_DEL : val = GCN_DEL; break; case API_KW_GET : val = GCN_RET; break; default : /* This should not happen! */ IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_createGCNOper: invalid operations code.\n" ); val = GCN_RET; break; } I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); /* ** Installation ID is currently ignored. */ val = STlength( install_id ) + 1; /* gcn_install.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( install_id, val, msg ); /* gcn_install.gcn_value */ msg += val; msgBuff->length += val; val = 1; /* gcn_tup_cnt */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); /* ** Node and connection operations have fixed types ** defined by GCN. For server operations, the server ** class is used as provided by the application. */ switch( parse->object ) { case API_KW_NODE : str = GCN_NODE; break; case API_KW_LOGIN : str = GCN_LOGIN; break; case API_KW_ATTR : str = GCN_ATTR; break; case API_KW_SERVER : str = ns_resolve_param( parse, API_FIELD_OBJ, FALSE ); break; default : /* Should not happen! */ IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_createGCNOper: invalid object.\n" ); str = empty; break; } /* ** Build the GCN tuple. */ val = STlength( str ) + 1; /* gcn_type.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( str, val, msg ); /* gcn_type.gcn_value */ msg += val; msgBuff->length += val; /* ** Use username if specified. This will ** either be the username we are connected ** with (if password also provided) or it ** will be the username for the GCN_UID_FLAG ** which requires special privileges for the ** current user. Otherwise, we use the user ** ID of the current process. */ if ( connHndl->ch_username ) str = connHndl->ch_username; else { if ( ! uid[0] ) { IDname( &puid ); STzapblank( uid, uid ); } str = uid; } val = STlength( str ) + 1; /* gcn_uid.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( str, val, msg ); /* gcn_uid.gcn_value */ msg += val; msgBuff->length += val; str = ns_resolve_param( parse, API_FIELD_VNODE, (parse->opcode != API_KW_ADD) ); val = STlength( str ) + 1; /* gcn_obj.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( str, val, msg ); /* gcn_obj.gcn_value */ msg += val; msgBuff->length += val; /* ** The tuple value must be built up from various parameters ** and can be function and object dependent. Call appropriate ** function for the current request to process the parameters. ** ** Pass in our temp buffer. It will be used if large enough ** or a different buffer will be allocated and returned. Check ** for memory allocation failures and free the returned buffer ** if it is not the one passed in (after copying the value). */ if ( ! (str = (*parse->parms->parms)( parse, sizeof( temp ), temp )) ) { IIapi_freeMsgBuffer( msgBuff ); return( NULL ); } val = STlength( str ) + 1; /* gcn_val.gcn_l_item */ I4ASSIGN_MACRO( val, *msg ); msg += sizeof( i4 ); msgBuff->length += sizeof( i4 ); MEcopy( str, val, msg ); /* gcn_val.gcn_value */ msgBuff->length += val; if ( str != temp ) MEfree( (PTR)str ); msgBuff->flags = IIAPI_MSG_EOD; return( msgBuff ); }
static II_BOOL cnvtGDV2DataValue ( IIAPI_STMTHNDL *stmtHndl, IIAPI_DESCRIPTOR *descriptor, IIAPI_MSG_BUFF *msgBuff, IIAPI_DATAVALUE *dataValue, II_BOOL compressed ) { i4 data_len, avail_len; /* ** Check that any minimum required length ** is available and determine GCA data length. */ switch( descriptor->ds_dataType ) { case IIAPI_VCH_TYPE : case IIAPI_VBYTE_TYPE : case IIAPI_NVCH_TYPE : case IIAPI_TXT_TYPE : case IIAPI_LTXT_TYPE : if ( ! compressed ) data_len = descriptor->ds_length; else { u_i2 len; /* ** The embeded length indicator is required. It may ** have been already loaded (dv_length > 0) or may ** be available in the input buffer. Otherwise, wait ** until it is available. */ if ( dataValue->dv_length ) MEcopy( dataValue->dv_value, sizeof( len ), (PTR)&len ); else if ( msgBuff->length >= sizeof( len ) ) MEcopy( (PTR)msgBuff->data, sizeof( len ), (PTR)&len ); else { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtGDV2DataValue: need embedded length (%d bytes, %d available)\n", sizeof( len ), msgBuff->length ); return( FALSE ); } /* ** Get the actual length of the compressed column. */ data_len = sizeof( len ) + (IIapi_isUCS2(descriptor->ds_dataType) ? len * 2 : len); } break; case IIAPI_LCLOC_TYPE : case IIAPI_LBLOC_TYPE : case IIAPI_LNLOC_TYPE : { i4 tag; u_i4 len0, len1; u_i1 *ptr = msgBuff->data; /* ** The ADF PERIPHERAL header must be read along with ** the ADP locator value. */ if ( msgBuff->length < (ADP_HDR_SIZE + sizeof(ADP_LOCATOR)) ) { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtGDV2DataValue: need LOCATOR (%d bytes, %d available)\n", ADP_HDR_SIZE + sizeof(ADP_LOCATOR), msgBuff->length ); return( FALSE ); } /* ** With the full ADP locator object available, read ** the header and set remaining data length. Column ** info is availabe once the header is read. */ msgBuff->data += ADP_HDR_SIZE; msgBuff->length -= ADP_HDR_SIZE; stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |= IIAPI_CI_AVAIL; MECOPY_CONST_MACRO( ptr, sizeof( tag ), (PTR)&tag ); if ( tag == ADP_P_LOCATOR ) { ptr += sizeof( tag ); MECOPY_CONST_MACRO( ptr, sizeof( len0 ), (PTR)&len0 ); ptr += sizeof( len0 ); MECOPY_CONST_MACRO( ptr, sizeof( len1 ), (PTR)&len1 ); stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |= IIAPI_CI_LOB_LENGTH; stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_data.lob_length = ((u_i8)len0 << 32) | (u_i8)len1; } data_len = sizeof( ADP_LOCATOR ); break; } default : data_len = descriptor->ds_length; break; } /* ** Determine amount of data available to be loaded: ** smaller of amount in input buffer and amount not ** yet loaded. */ avail_len = min( msgBuff->length, data_len - dataValue->dv_length ); IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtGDV2DataValue: loading %d of %d bytes (%d loaded)\n", avail_len, data_len, (II_LONG)dataValue->dv_length ); /* ** Load available data in input buffer. */ if ( avail_len ) { MEcopy( (PTR)msgBuff->data, avail_len, (PTR)((char *)dataValue->dv_value + dataValue->dv_length) ); msgBuff->data += avail_len; msgBuff->length -= avail_len; dataValue->dv_length += avail_len; } /* ** Check to see if all data has been loaded. */ if ( dataValue->dv_length < data_len ) { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtGDV2DataValue: insufficient data: need %d bytes\n", data_len - dataValue->dv_length ); return( FALSE ); } /* ** For nullable columns, check the NULL byte. */ if ( descriptor->ds_nullable ) { /* ** Check to see if NULL byte is in input buffer. */ if ( ! msgBuff->length ) { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtGDV2DataValue: need NULL byte (1 byte, 0 available\n" ); return( FALSE ); } if ( ! (*msgBuff->data & ADF_NVL_BIT) ) dataValue->dv_null = FALSE; else { dataValue->dv_null = TRUE; dataValue->dv_length = 0; /* Force to 0 since set above */ } msgBuff->data++; /* Remove NULL byte from input buffer */ msgBuff->length--; } if ( IIapi_isVAR( descriptor->ds_dataType ) && ! dataValue->dv_null ) { /* ** Variable length types only return the length of ** the actual data, not their fully padded length. */ u_i2 len; MEcopy( dataValue->dv_value, sizeof( len ), (PTR)&len ); dataValue->dv_length = sizeof( len ) + (IIapi_isUCS2( descriptor->ds_dataType ) ? len * 2 : len); } return( TRUE ); }
II_EXTERN IIAPI_STATUS IIapi_getNSDescriptor( IIAPI_STMTHNDL *stmtHndl ) { API_PARSE *parse = (API_PARSE *)stmtHndl->sh_queryText; IIAPI_DESCRIPTOR *desc1, *desc2; STATUS status; i4 count; switch( parse->object ) { case API_KW_NODE : desc1 = ns_node_desc; count = ARRAY_SIZE( ns_node_desc ); break; case API_KW_LOGIN : desc1 = ns_login_desc; count = ARRAY_SIZE( ns_login_desc ); break; case API_KW_ATTR : desc1 = ns_attr_desc; count = ARRAY_SIZE( ns_attr_desc ); break; case API_KW_SERVER : desc1 = ns_server_desc; count = ARRAY_SIZE( ns_server_desc ); break; default : /* ** Should not happen! */ IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_getNSDescriptor: invalid object.\n" ); return( IIAPI_ST_FAILURE ); break; } stmtHndl->sh_colDescriptor = (IIAPI_DESCRIPTOR *) MEreqmem( 0, sizeof(IIAPI_DESCRIPTOR) * count, FALSE, &status ); if ( ! stmtHndl->sh_colDescriptor ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_getNSDescriptor: error allocating descriptor.\n" ); return( IIAPI_ST_OUT_OF_MEMORY ); } for( stmtHndl->sh_colCount = 0, desc2 = stmtHndl->sh_colDescriptor; stmtHndl->sh_colCount < count; stmtHndl->sh_colCount++, desc1++, desc2++ ) { STRUCT_ASSIGN_MACRO( *desc1, *desc2 ); desc2->ds_columnName = STalloc( desc1->ds_columnName ); if ( ! desc2->ds_columnName ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_getNSDescriptor: error allocating column name.\n" ); /* ** Since all the entries are valid ** upto sh_colCount, we'll leave the ** descriptor to be freed when the ** statement handle is freed. */ return( IIAPI_ST_OUT_OF_MEMORY ); } } return( IIAPI_ST_SUCCESS ); }
static II_BOOL cnvtBLOB2DataValue ( IIAPI_STMTHNDL *stmtHndl, IIAPI_DESCRIPTOR *descriptor, IIAPI_MSG_BUFF *msgBuff, IIAPI_DATAVALUE *dataValue ) { u_i2 char_size = IIapi_isUCS2( descriptor->ds_dataType ) ? 2 : 1; i4 indicator = 0; i4 length; u_i2 seg_len; /* ** The output buffer needs to be initialized with a ** zero length segment. Subsequent processing then ** only needs to append input segments to the current ** output segment. The initial output data value ** length is set to 0 (see IIapi_getColumns()) so ** that we can detect when initialization is required. ** Any non-zero value indicates an existing segment. */ if ( ! dataValue->dv_length ) { seg_len = 0; dataValue->dv_null = FALSE; dataValue->dv_length = sizeof( seg_len ); MECOPY_CONST_MACRO( (PTR)&seg_len, sizeof( seg_len ), dataValue->dv_value ); } /* ** The MORE_SEGMENTS flag gets set once the BLOB ** header is read. If it is not set, we need to ** read the header. */ if ( ! ( stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS ) ) { i4 tag; u_i4 len0, len1; u_i1 *ptr = msgBuff->data; /* ** BLOB processing assumes that if this is a NULL or ** zero length BLOB, the entire BLOB is processed with ** the header information. In addition to the header, ** we need to have access to the first segment indicator ** and possibly the NULL byte. Note that if the BLOB ** is nullable but not NULL, the additional byte will ** come from the segment length of the first segment. */ length = ADP_HDR_SIZE + sizeof( indicator ) + (descriptor->ds_nullable ? 1 : 0); if ( msgBuff->length < length ) { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtBLOB2DataValue: need BLOB header for column %d\n", (II_LONG)stmtHndl->sh_colIndex ); return( FALSE ); } /* ** Remove the header from the input buffer. LOB ** column info is available once the header has ** been read. Extract header data as column info. */ msgBuff->data += ADP_HDR_SIZE; msgBuff->length -= ADP_HDR_SIZE; stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |= IIAPI_CI_AVAIL; MECOPY_CONST_MACRO( ptr, sizeof( tag ), (PTR)&tag ); if ( tag == ADP_P_GCA ) { ptr += sizeof( tag ); MECOPY_CONST_MACRO( ptr, sizeof( len0 ), (PTR)&len0 ); ptr += sizeof( len0 ); MECOPY_CONST_MACRO( ptr, sizeof( len1 ), (PTR)&len1 ); stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |= IIAPI_CI_LOB_LENGTH; stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_data.lob_length = ((u_i8)len0 << 32) | (u_i8)len1; } IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtBLOB2DataValue: processed BLOB header for column %d\n", (II_LONG)stmtHndl->sh_colIndex ); /* ** At this point we begin processing segments. */ stmtHndl->sh_flags |= IIAPI_SH_MORE_SEGMENTS; } /* ** Process the segment indicator. */ length = sizeof( indicator ); if ( msgBuff->length >= length ) { /* ** To consume the indicator, must have sufficient remaining ** data to satisfy the request. There are three cases: ** ** Indicator value Nullable Bytes Needed ** --------------- -------- ------------ ** 0 N 0 ** 0 Y 1 (NULL byte) ** 1 Y/N 3 (segment length + data) */ MECOPY_CONST_MACRO( msgBuff->data, length, (PTR)&indicator ); length += indicator ? sizeof( seg_len ) + char_size : (descriptor->ds_nullable ? 1 : 0); } if ( msgBuff->length < length ) { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ("cnvtBLOB2DataValue: need segment indicator for column %d\n", (II_LONG)stmtHndl->sh_colIndex); return( FALSE ); } /* ** Remove the indicator from the input buffer. */ msgBuff->data += sizeof( indicator ); msgBuff->length -= sizeof( indicator ); /* ** If the indicator is 0, this is the end of the ** data segments and the BLOB. Otherwise a ** segment follows. */ if ( ! indicator ) { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtBLOB2DataValue: found end-of-segments indicator\n" ); /* ** During purging we ignore the NULL byte since ** the data value was initialized when purging ** started. */ if ( ! (stmtHndl->sh_flags & IIAPI_SH_PURGE_SEGMENTS) ) dataValue->dv_null = descriptor->ds_nullable ? IIAPI_ISNULL(-descriptor->ds_dataType, 1, msgBuff->data) : FALSE; /* ** Remove NULL byte from input buffer and ** terminate BLOB segment processing. */ if ( descriptor->ds_nullable ) { msgBuff->data++; msgBuff->length--; } stmtHndl->sh_flags &= ~(IIAPI_SH_MORE_SEGMENTS | IIAPI_SH_PURGE_SEGMENTS); } else { /* ** Read the segment length. Limit the length ** to what is available in the input buffer. */ MECOPY_CONST_MACRO( msgBuff->data, sizeof( seg_len ), (PTR)&seg_len ); msgBuff->data += sizeof( seg_len ); msgBuff->length -= sizeof( seg_len ); length = min( seg_len, msgBuff->length / char_size ) * char_size; if ( stmtHndl->sh_flags & IIAPI_SH_PURGE_SEGMENTS ) { /* ** Remove the available portion of ** the segment from the input buffer. */ msgBuff->data += length; msgBuff->length -= length; stmtHndl->sh_flags |= IIAPI_SH_LOST_SEGMENTS; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtBLOB2DataValue: discarding segment of %d bytes\n", length ); } else { u_i2 new_len; /* ** We further limit the segment length to be ** processed by the space available in the ** output buffer. */ length = min(length, descriptor->ds_length - dataValue->dv_length); length -= length % char_size; /* Whole characters only */ /* ** Append input segment data to output segment. */ MEcopy( msgBuff->data, length, (PTR)((char *)dataValue->dv_value + dataValue->dv_length) ); msgBuff->data += length; msgBuff->length -= length; dataValue->dv_length += length; /* ** Update the output embedded segment length. */ new_len = (dataValue->dv_length - sizeof( new_len )) / char_size; MECOPY_CONST_MACRO( (PTR)&new_len, sizeof( new_len ), dataValue->dv_value ); IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtBLOB2DataValue: processed segment of %d bytes\n", length ); } /* ** If the entire input segment was not consumed, ** patch what remains to be a valid BLOB segment. ** Create a segment indicator and segment length ** to represent the remaining data. There is ** room in the input buffer for this info to be ** pre-pended to what remains since the same ** info was removed from the input buffer above. */ if ( (length /= char_size) != seg_len ) { seg_len -= length; /* Segment length */ msgBuff->data -= sizeof( seg_len ); msgBuff->length += sizeof( seg_len ); MECOPY_CONST_MACRO((PTR)&seg_len, sizeof(seg_len), msgBuff->data); msgBuff->data -= sizeof( indicator ); /* Indicator */ msgBuff->length += sizeof( indicator ); MECOPY_CONST_MACRO( (PTR)&indicator, sizeof( indicator ), msgBuff->data ); IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "cnvtBLOB2DataValue: split segment, %d bytes remain\n", (II_LONG)seg_len ); } } return( TRUE ); }
II_EXTERN II_VOID II_FAR II_EXPORT IIapi_position( IIAPI_POSPARM II_FAR *posParm ) { IIAPI_STMTHNDL *stmtHndl; IIAPI_CONNHNDL *connHndl; bool valid; IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_position: position cursor\n" ); /* ** Validate Input parameters */ if ( ! posParm ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_position: null posParms parameters\n" ); return; } posParm->po_genParm.gp_completed = FALSE; posParm->po_genParm.gp_status = IIAPI_ST_SUCCESS; posParm->po_genParm.gp_errorHandle = NULL; stmtHndl = (IIAPI_STMTHNDL *)posParm->po_stmtHandle; /* ** Make sure API is initialized */ if ( ! IIapi_initialized() ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_position: API is not initialized\n" ); IIapi_appCallback( &posParm->po_genParm, NULL, IIAPI_ST_NOT_INITIALIZED ); return; } if ( ! IIapi_isStmtHndl( stmtHndl ) || IIAPI_STALE_HANDLE( stmtHndl ) || ! (connHndl = IIapi_getConnHndl( (IIAPI_HNDL *)stmtHndl )) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_position: invalid handle %p\n", stmtHndl ); IIapi_appCallback( &posParm->po_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_position: handle = %p\n", stmtHndl ); IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_position: reference = %d, offset = %d, rows = %d\n", posParm->po_reference, posParm->po_offset, posParm->po_rowCount ); IIapi_clearAllErrors( (IIAPI_HNDL *)stmtHndl ); /* ** Validate parameters. */ switch( posParm->po_reference ) { case IIAPI_POS_BEGIN : case IIAPI_POS_END : if ( connHndl->ch_partnerProtocol >= GCA_PROTOCOL_LEVEL_67 ) valid = TRUE; else { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_scroll: scrolling not supported\n" ); valid = FALSE; } break; case IIAPI_POS_CURRENT : if ( connHndl->ch_partnerProtocol >= GCA_PROTOCOL_LEVEL_67 || posParm->po_offset == 1 ) valid = TRUE; else { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_scroll: scrolling not supported\n" ); valid = FALSE; } break; default : IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_position: invalid reference: %d\n", (II_LONG)posParm->po_reference ); valid = FALSE; break; } if ( posParm->po_rowCount < ((connHndl->ch_partnerProtocol >= GCA_PROTOCOL_LEVEL_67) ? 0 : 1) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_position: invalid row count: %d\n", (II_LONG)posParm->po_rowCount ); valid = FALSE; } if ( ! valid ) { if ( ! IIapi_localError( (IIAPI_HNDL *)stmtHndl, E_AP0011_INVALID_PARAM_VALUE, II_SS22003_NUM_VAL_OUT_OF_RANGE, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &posParm->po_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &posParm->po_genParm, (IIAPI_HNDL *)stmtHndl, IIAPI_ST_FAILURE); return; } IIapi_uiDispatch( IIAPI_EV_POSITION_FUNC, (IIAPI_HNDL *) stmtHndl, (II_PTR)posParm ); return; }
II_EXTERN II_VOID IIapi_loadColumns ( IIAPI_STMTHNDL *stmtHndl, IIAPI_GETCOLPARM *getColParm, IIAPI_MSG_BUFF *msgBuff ) { /* ** If no data available or request complete, we be done! */ if ( msgBuff->length < 1 || ! stmtHndl->sh_colFetch || getColParm->gc_rowsReturned >= getColParm->gc_rowCount ) { IIAPI_TRACE( IIAPI_TR_DETAIL ) ( "IIapi_loadColumns: nothing to do\n" ); return; } IIAPI_TRACE( IIAPI_TR_DETAIL ) ( "IIapi_loadColumns: converting tuple data to API format\n" ); /* ** Loop for each row in the request. */ do { /* ** Process columns in the current row. The current ** column request should not span rows, but may be ** fewer than the remaining columns in the row. If ** this is a multi-row fetch, we will reset the ** column request for the next row after processing ** the current row. The current row request will ** either be satisfied, or the tuple data will be ** exhausted. */ load_columns( stmtHndl, getColParm, msgBuff ); /* ** If there are still columns to be processed in ** the current request, exit to get more data. */ if ( stmtHndl->sh_colFetch ) break; /* ** We have completed the request for the current row. ** We bump the number of rows returned since we either ** completed a row or completed a partial fetch of a ** row. We will either exit at this point or move ** on to the next row. */ getColParm->gc_rowsReturned++; /* ** Check to see if we have completed a row. */ if ( stmtHndl->sh_colIndex >= stmtHndl->sh_colCount ) { /* ** For cursors, decrement the remaining row count now ** that a row has been completed. */ if ( stmtHndl->sh_flags & IIAPI_SH_CURSOR ) stmtHndl->sh_rowCount--; /* ** Set the column index for the start of the next row. ** If there are more rows in the request, set the ** column fetch count for the next row. */ stmtHndl->sh_colIndex = 0; if ( getColParm->gc_rowsReturned < getColParm->gc_rowCount ) stmtHndl->sh_colFetch = stmtHndl->sh_colCount; } } while( stmtHndl->sh_colFetch ); return; }
II_EXTERN II_VOID II_FAR II_EXPORT IIapi_autocommit( IIAPI_AUTOPARM II_FAR *autoParm ) { IIAPI_TRANHNDL *tranHndl; IIAPI_CONNHNDL *connHndl; IIAPI_TRACE( IIAPI_TR_TRACE )("IIapi_autocommit: set autocommit state\n"); /* ** Validate Input parameters */ if ( ! autoParm ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_autocommit: null autocommit parameters\n" ); return; } autoParm->ac_genParm.gp_completed = FALSE; autoParm->ac_genParm.gp_status = IIAPI_ST_SUCCESS; autoParm->ac_genParm.gp_errorHandle = NULL; connHndl = (IIAPI_CONNHNDL *)autoParm->ac_connHandle; tranHndl = (IIAPI_TRANHNDL *)autoParm->ac_tranHandle; /* ** Make sure API is initialized */ if ( ! IIapi_initialized() ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_autocommit: API is not initialized\n" ); IIapi_appCallback( &autoParm->ac_genParm, NULL, IIAPI_ST_NOT_INITIALIZED ); return; } if ( ! connHndl && ! tranHndl ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_autocommit: no handle provided\n" ); IIapi_appCallback( &autoParm->ac_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } if ( connHndl && (! IIapi_isConnHndl( connHndl ) || IIAPI_STALE_HANDLE( connHndl )) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_autocommit: invalid connection handle\n" ); IIapi_appCallback( &autoParm->ac_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } if ( tranHndl && (! IIapi_isTranHndl( tranHndl ) || IIAPI_STALE_HANDLE( tranHndl )) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_autocommit: invalid transaction handle\n" ); IIapi_appCallback( &autoParm->ac_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_autocommit: connHndl = %p, tranHndl = %p\n", autoParm->ac_connHandle, autoParm->ac_tranHandle ); if ( connHndl ) IIapi_clearAllErrors( (IIAPI_HNDL *)connHndl ); if ( tranHndl ) IIapi_clearAllErrors( (IIAPI_HNDL *)tranHndl ); if ( ! tranHndl && ! IIapi_isQueEmpty( &connHndl->ch_tranHndlList ) ) { /* ** Application is attempting to enable autocommit mode ** with an active transaction. */ IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_autocommit: can't enable autocommit in a transaction\n" ); if ( ! IIapi_localError( (IIAPI_HNDL *)connHndl, E_AP0003_ACTIVE_TRANSACTIONS, II_SS25000_INV_XACT_STATE, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &autoParm->ac_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &autoParm->ac_genParm, (IIAPI_HNDL *)connHndl, IIAPI_ST_FAILURE ); return; } if ( tranHndl && ! IIapi_isQueEmpty( &tranHndl->th_stmtHndlList ) ) { /* ** Application is attempting to disable autocommit mode ** with active statements. */ IIAPI_TRACE( IIAPI_TR_ERROR ) ("IIapi_autocommit: can't disable autocommit with active statements\n"); if ( ! IIapi_localError( (IIAPI_HNDL *)tranHndl, E_AP0004_ACTIVE_QUERIES, II_SS25000_INV_XACT_STATE, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &autoParm->ac_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &autoParm->ac_genParm, (IIAPI_HNDL *)tranHndl, IIAPI_ST_FAILURE ); return; } if ( ! tranHndl ) { /* ** Enable autocommit mode. Create a transaction handle ** and return it to the application. */ if ( ! ( tranHndl = IIapi_createTranHndl( NULL, connHndl ) ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_autocommit: createTranHndl failed\n" ); IIapi_appCallback( &autoParm->ac_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); return; } autoParm->ac_tranHandle = (II_PTR)tranHndl; } else { /* ** Disable autocommit mode. The transaction handle ** will be deleted, so clear the output parameter. */ autoParm->ac_tranHandle = NULL; } IIapi_uiDispatch( IIAPI_EV_AUTO_FUNC, (IIAPI_HNDL *)tranHndl, (II_PTR)autoParm ); return; }
static II_VOID load_columns ( IIAPI_STMTHNDL *stmtHndl, IIAPI_GETCOLPARM *getColParm, IIAPI_MSG_BUFF *msgBuff ) { IIAPI_DESCRIPTOR *descr; IIAPI_DATAVALUE *value; i4 length; u_i2 len; bool done; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "IIapi_loadColumns: %d columns starting with %d, %d total columns\n", (II_LONG)stmtHndl->sh_colFetch, (II_LONG)stmtHndl->sh_colIndex, (II_LONG)stmtHndl->sh_colCount ); descr = &stmtHndl->sh_colDescriptor[ stmtHndl->sh_colIndex ]; value = &getColParm->gc_columnData[ (getColParm->gc_rowsReturned * getColParm->gc_columnCount) + getColParm->gc_columnCount - stmtHndl->sh_colFetch ]; /* ** Process columns until all done or input buffer exhausted. */ for( ; stmtHndl->sh_colFetch; stmtHndl->sh_colFetch--, stmtHndl->sh_colIndex++, descr++, value++ ) { /* ** Clear column info at start of row. The more segments ** flag must not be set otherwise the first column is a ** LOB which has already been partially processed. There ** must also be at least some data available for the first ** column, otherwise we may be clearing the info when the ** last row has already been received. */ if ( stmtHndl->sh_colIndex == 0 && ! (stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS) && msgBuff->length > 0 ) { i2 i; for( i = 0; i < stmtHndl->sh_colCount; i++ ) stmtHndl->sh_colInfo[ i ].ci_flags = 0; } /* ** Blobs are broken into segments of variable lengths ** and require special handling to load segments using ** internal data value info. */ if ( IIapi_isBLOB( descr->ds_dataType ) ) done = load_blob( stmtHndl, getColParm, descr, msgBuff, value ); else done = cnvtGDV2DataValue( stmtHndl, descr, msgBuff, value, (stmtHndl->sh_flags & IIAPI_SH_COMP_VARCHAR) ? TRUE : FALSE ); if ( ! done ) break; /* Need more data for current column */ stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |= IIAPI_CI_AVAIL; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "IIapi_loadColumns: loaded data for column %d\n", (II_LONG)stmtHndl->sh_colIndex ); } return; }
II_EXTERN II_BOOL IIapi_termAPI( IIAPI_ENVHNDL *envHndl ) { IIAPI_ENVHNDL *defEnvHndl; II_BOOL last_term = FALSE; if ( ! IIapi_static ) return( TRUE ); defEnvHndl = IIapi_defaultEnvHndl(); if ( envHndl ) { /* ** Free the environment handle. */ MUp_semaphore( &IIapi_static->api_semaphore ); QUremove( (QUEUE *)envHndl ); MUv_semaphore( &IIapi_static->api_semaphore ); IIapi_deleteEnvHndl( envHndl ); } else { /* ** Decrement the usage counter in ** the default environment handle. */ MUp_semaphore( &defEnvHndl->en_semaphore ); defEnvHndl->en_initCount = max( 0, defEnvHndl->en_initCount - 1 ); MUv_semaphore( &defEnvHndl->en_semaphore ); } /* ** Shutdown API when all version 1 initializers have terminated ** and there are no active version 2 environments. */ if ( ! defEnvHndl->en_initCount && IIapi_isQueEmpty( &IIapi_static->api_env_q ) ) { QUEUE *q; IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_termAPI: shutting down API completely.\n" ); /* ** Free the default environment. */ IIapi_deleteEnvHndl( (IIAPI_ENVHNDL *)IIapi_static->api_env_default ); IIapi_static->api_env_default = NULL; /* ** Shutdown sub-systems. */ IIapi_termGCA(); IIapi_termADF(); IIAPI_TRACE( IIAPI_TR_INFO )( "IIapi_termAPI: API shutdown.\n" ); IIAPI_TERMTRACE(); /* ** Free the remaining global resources. */ if (IIapi_static->api_ucode_ctbl) MEfree (IIapi_static->api_ucode_ctbl); if (IIapi_static->api_ucode_cvtbl) MEfree (IIapi_static->api_ucode_cvtbl); MEtls_destroy( &IIapi_static->api_thread, MEfree ); MUr_semaphore( &IIapi_static->api_semaphore ); MEfree( (PTR)IIapi_static ); IIapi_static = NULL; last_term = TRUE; } return( last_term ); }
static II_VOID checkBLOBSegment ( IIAPI_STMTHNDL *stmtHndl, IIAPI_DESCRIPTOR *descriptor, IIAPI_MSG_BUFF *msgBuff ) { i4 indicator; i4 length = sizeof( indicator ); /* ** We only check when we know it is safe to do so. ** We must be reading segments, but not purging. ** and we require the request to be complete to ** avoid scenarios to complicated to explain or ** properly handle. */ if ( stmtHndl->sh_flags & IIAPI_SH_MORE_SEGMENTS && ! ( stmtHndl->sh_flags & IIAPI_SH_PURGE_SEGMENTS ) && ! stmtHndl->sh_colFetch && msgBuff->length >= length ) { /* ** Peak at the indicator. */ MECOPY_CONST_MACRO( msgBuff->data, length, (PTR)&indicator ); if ( ! indicator ) { /* ** We have the end-of-segments indicator. ** Only consume it if the (optional) null ** byte is also available (if not nullable, ** the test is redundant). The null byte ** value is ignored (see description). */ if ( descriptor->ds_nullable ) length++; if ( msgBuff->length >= length ) { IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "checkBLOBSegment: found end-of-segments\n" ); msgBuff->data += length; msgBuff->length -= length; /* ** Since we have now finished the BLOB, ** advance the column index to the next ** column (wrap if finished all columns). ** Since we check for sh_colFetch to be ** 0, we assume the gc_rowsReturned is ** set properly and we are not in the ** midst of a multi-row fetch. */ stmtHndl->sh_colInfo[ stmtHndl->sh_colIndex ].ci_flags |= IIAPI_CI_AVAIL; if ( ++stmtHndl->sh_colIndex >= stmtHndl->sh_colCount ) { /* SD issue 142188; Bug 123159. ** Decrement the row count when the tuple is ** completed. */ if ( stmtHndl->sh_flags & IIAPI_SH_CURSOR ) stmtHndl->sh_rowCount--; stmtHndl->sh_colIndex = 0; } stmtHndl->sh_flags &= ~IIAPI_SH_MORE_SEGMENTS; } } } return; }
static STATUS ns_validate( API_PARSE *parse, i4 *keyword ) { i4 i; /* ** Validate keywords. This is a little bit more ** complicated than Netutil since we support the ** SERVER object and parameter markers for type. ** Keywords (except for type) cannot be provided ** through parameters. ** ** Field syntax and semantics: ** ** <function> <type> <object> [<value>...] ** ** Function, type and object must be provided. ** Function cannot be provided in a parameter. ** Type can be provided in a parameter. Values ** may be parameters and do not contain keywords. ** ** The SERVER keyword may replace type (but not in ** a parameter), and object (server class) may then ** be provided in a parameter. Otherwise, object ** cannot be provided in a parameter. */ if ( parse->field_count < 3 ) return( E_AP0010_INVALID_COLUMN_COUNT ); if ( keyword[ API_FIELD_FUNC ] == INVALID_KEYWORD || keyword[ API_FIELD_FUNC ] == API_KW_PARAM ) return( E_AP0011_INVALID_PARAM_VALUE ); else parse->opcode = keyword[ API_FIELD_FUNC ]; if ( keyword[ API_FIELD_TYPE ] == INVALID_KEYWORD ) return( E_AP0011_INVALID_PARAM_VALUE ); if ( keyword[ API_FIELD_TYPE ] == API_KW_SERVER ) if ( keyword[ API_FIELD_OBJ ] != INVALID_KEYWORD && keyword[ API_FIELD_OBJ ] != API_KW_PARAM ) return( E_AP0011_INVALID_PARAM_VALUE ); else { parse->type = API_KW_PRIVATE; /* Default for servers */ parse->object = API_KW_SERVER; } else if ( keyword[ API_FIELD_OBJ ] == INVALID_KEYWORD || keyword[ API_FIELD_OBJ ] == API_KW_PARAM ) return( E_AP0011_INVALID_PARAM_VALUE ); else { parse->type = keyword[ API_FIELD_TYPE ]; parse->object = keyword[ API_FIELD_OBJ ]; } /* ** Make sure enough fields have been provided ** (or will be provided through query parameters). ** Parameter count dependent on the function and ** object. Optional parameters supported. */ for( i = 0; i < ARRAY_SIZE( ns_parms ); i++ ) if ( ns_parms[ i ].opcode == parse->opcode && ns_parms[ i ].object == parse->object ) { parse->parms = &ns_parms[ i ]; if ( parse->field_count < ns_parms[ i ].parm_min || parse->field_count > ns_parms[ i ].parm_max ) { return( E_AP0010_INVALID_COLUMN_COUNT ); } break; } if ( i >= ARRAY_SIZE( ns_parms ) ) { /* ** This shouldn't happen. */ IIAPI_TRACE( IIAPI_TR_FATAL ) ( "ns_validate: couldn't find parameter info for request\n" ); return( E_AP0011_INVALID_PARAM_VALUE ); } return( OK ); }
II_EXTERN II_VOID II_FAR II_EXPORT IIapi_putColumns( IIAPI_PUTCOLPARM II_FAR *putColParm ) { IIAPI_STMTHNDL *stmtHndl; II_ULONG err_code; IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_putColumns: sending tuple to server\n" ); /* ** Validate Input parameters */ if ( ! putColParm ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_putColumns: null putColumns parameters\n" ); return; } putColParm->pc_genParm.gp_completed = FALSE; putColParm->pc_genParm.gp_status = IIAPI_ST_SUCCESS; putColParm->pc_genParm.gp_errorHandle = NULL; stmtHndl = (IIAPI_STMTHNDL *)putColParm->pc_stmtHandle; /* ** Make sure API is initialized */ if ( ! IIapi_initialized() ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_putColumns: API is not initialized\n" ); IIapi_appCallback( &putColParm->pc_genParm, NULL, IIAPI_ST_NOT_INITIALIZED ); return; } if ( ! IIapi_isStmtHndl( stmtHndl ) || IIAPI_STALE_HANDLE( stmtHndl ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_putColumns: invalid statement handle\n" ); IIapi_appCallback( &putColParm->pc_genParm, NULL, IIAPI_ST_INVALID_HANDLE ); return; } IIAPI_TRACE( IIAPI_TR_INFO ) ( "IIapi_putColumns: stmtHndl = %p\n", stmtHndl ); IIapi_clearAllErrors( (IIAPI_HNDL *)stmtHndl ); if ( ! IIapi_validPColCount( stmtHndl, putColParm ) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ("IIapi_putColumns: invalid count: %d (actual %d, index %d)\n", (II_LONG)putColParm->pc_columnCount, (II_LONG)stmtHndl->sh_colCount, (II_LONG)stmtHndl->sh_colIndex ); if ( ! IIapi_localError( (IIAPI_HNDL *)stmtHndl, E_AP0010_INVALID_COLUMN_COUNT, II_SS21000_CARD_VIOLATION, IIAPI_ST_FAILURE ) ) IIapi_appCallback( &putColParm->pc_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); else IIapi_appCallback( &putColParm->pc_genParm, (IIAPI_HNDL *)stmtHndl, IIAPI_ST_FAILURE ); return; } if ( (err_code = IIapi_validDataValue( putColParm->pc_columnCount, &stmtHndl->sh_colDescriptor[ stmtHndl->sh_colIndex ], putColParm->pc_columnData )) != OK ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_putColumns: column data conflicts with descriptor\n" ); /* ** We only issue a warning on data conflicts, but if the ** warning can't be generated then abort the operation. */ if ( ! IIapi_localError( (IIAPI_HNDL *)stmtHndl, err_code, II_SS22500_INVALID_DATA_TYPE, IIAPI_ST_WARNING ) ) { IIapi_appCallback( &putColParm->pc_genParm, NULL, IIAPI_ST_OUT_OF_MEMORY ); return; } } stmtHndl->sh_colFetch = putColParm->pc_columnCount; IIapi_uiDispatch( IIAPI_EV_PUTCOLUMN_FUNC, (IIAPI_HNDL *)stmtHndl, (II_PTR)putColParm ); return; }