| /********************************************************************** |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| // |
| **********************************************************************/ |
| /* -*-C++-*- |
| ***************************************************************************** |
| * |
| * File: SqlCmd.C |
| * RCS: $Id: SqlCmd.cpp,v 1.1 2007/10/09 19:40:29 Exp $ |
| * Description: |
| * |
| * |
| * Created: 4/15/95 |
| * Modified: $ $Date: 2007/10/09 19:40:29 $ (GMT) |
| * Language: C++ |
| * Status: $State: Exp $ |
| * |
| * |
| * |
| * |
| ***************************************************************************** |
| */ |
| |
| |
| #include "Platform.h" |
| |
| #include <ctype.h> |
| #include <iostream> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sstream> |
| #include <unistd.h> |
| |
| #include "ComAnsiNamePart.h" |
| #include "ComGuardianFileNameParts.h" |
| #include "ComASSERT.h" |
| #include "Formatter.h" |
| #include "SqlciStats.h" |
| #include "NAString.h" |
| #include "ErrorMessage.h" // NAWriteConsole |
| #include "IntervalType.h" // NAType::convertTypeToText etc. |
| #include "SqlciError.h" |
| #include "SQLCLIdev.h" |
| #include "sqlcmd.h" |
| #include "sql_id.h" |
| #include "ComSqlId.h" |
| #include "ComRtUtils.h" |
| #define CAT_MAX_HEADING_LEN 132 |
| #define CM_GUA_ENAME_LEN 36 |
| #include "dfs2rec.h" |
| #include "ex_error.h" |
| #include "str.h" |
| #include "stringBuf.h" |
| #include "charinfo.h" |
| #include "NLSConversion.h" |
| #include "nawstring.h" |
| #include "SqlciList_templ.h" |
| #include "ComCextMisc.h" |
| #include "ComCextdecs.h" |
| |
| #include "ComQueue.h" |
| #include "ExExeUtilCli.h" |
| |
| extern SqlciEnv * global_sqlci_env; // global sqlci_env for break key handling purposes. |
| extern ComDiagsArea sqlci_DA; |
| extern NAHeap sqlci_Heap; |
| extern BOOL WINAPI CtrlHandler (DWORD signalType); |
| const Lng32 BREAK_ERROR = -999; |
| |
| const Int32 MAX_MSGTEXT_LEN = 4096; |
| const Int32 MAX_OTHERBUF_LEN = ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1+1; |
| |
| // These should come from a SQL Message Text (immudefs) file! ## |
| #define UNLOADED_MESSAGE "--- %ld row(s) unloaded." |
| #define LOADED_MESSAGE "--- %ld row(s) loaded." |
| #define SELECTED_MESSAGE "--- %d row(s) selected." |
| #define SELECTED_BUT_MESSAGE "--- %d row(s) selected (but none displayed)." |
| #define SELECTED_FIRST_ROW_DISPLAY_MESSAGE "--- %d row(s) selected (and first row displayed)." |
| #define INSERTED_MESSAGE "--- %ld row(s) inserted." |
| #define UPDATED_MESSAGE "--- %ld row(s) updated." |
| #define DELETED_MESSAGE "--- %ld row(s) deleted." |
| #define OP_COMPLETE_MESSAGE "--- SQL operation complete." |
| #define OP_COMPLETED_ERRORS "--- SQL operation failed with errors." |
| #define OP_COMPLETED_WARNINGS "--- SQL operation completed with warnings." |
| #define PREPARED_MESSAGE "--- SQL command prepared." |
| #define LISTCOUNT_MESSAGE " LIST_COUNT was reached." |
| #define CATAPI "CREATE TANDEM_CAT_REQUEST&" |
| |
| |
| // These static variables and global functions, in conjunction with their |
| // callers, have as one goal to nicely format blank lines for sqlci output |
| // (output to screen and to logfile -- which should be identical): |
| // We want single blank lines to enhance legibility; we never want two |
| // blank non-data lines in a row. |
| |
| static Lng32 worstcode; |
| static NABoolean lastLineWasABlank; |
| |
| // remember the number of rows affected by an SQL statement |
| // before resetting the diagnostics info |
| static Int64 rowsAffected; |
| |
| #define Succ_or_Warn (retcode == SQL_Success || (retcode >= 0 && retcode != SQL_Eof)) |
| void HandleCLIErrorInit() |
| { |
| ComASSERT(SQL_Error < SQL_Warning && SQL_Warning < SQL_Eof); |
| worstcode = SQL_Eof; |
| lastLineWasABlank = FALSE; |
| |
| } |
| |
| void SqlCmd::clearCLIDiagnostics() |
| { |
| SQLSTMT_ID dummy_stmt; |
| SQLMODULE_ID module; |
| init_SQLMODULE_ID(&module); |
| |
| init_SQLSTMT_ID(&dummy_stmt, |
| SQLCLI_CURRENT_VERSION, |
| stmt_handle, |
| &module |
| ); |
| |
| SQL_EXEC_ClearDiagnostics(&dummy_stmt); |
| } |
| |
| volatile Int32 breakReceived = 0; |
| |
| void HandleCLIError(SQLSTMT_ID *stmt, Lng32 &error, SqlciEnv *sqlci_env, |
| NABoolean displayErr, NABoolean * isEOD, |
| Int32 prepcode) |
| { |
| Int32 diagsCondCount = 0; |
| if (error == 100) |
| diagsCondCount = getDiagsCondCount(stmt); |
| // Get Warnings only when there are 2 or more conditions. |
| // One condition is for the error code 100 and the others are the actual warnings |
| NABoolean getWarningsWithEOF = (diagsCondCount > 1); |
| HandleCLIError(error, sqlci_env, displayErr, isEOD, prepcode, getWarningsWithEOF); |
| } |
| |
| void HandleCLIError(Lng32 &error, SqlciEnv *sqlci_env, |
| NABoolean displayErr, NABoolean * isEOD, |
| Int32 prepcode, NABoolean getWarningsWithEOF) |
| { |
| if (error == 100) |
| { |
| if (isEOD != NULL) |
| *isEOD = 1; |
| if (! getWarningsWithEOF) { |
| SqlCmd::clearCLIDiagnostics(); |
| return; |
| } |
| } |
| if (isEOD) |
| *isEOD = 0; |
| |
| if (error == BREAK_ERROR) |
| { |
| DWORD dwd = 0; |
| CtrlHandler(dwd); |
| } |
| else |
| #define MXCI_DONOTISSUE_ERRMSGS -1 |
| |
| if (error != 0) |
| { |
| |
| Logfile *log = sqlci_env->get_logfile(); |
| |
| if (error != SQL_Eof) |
| worstcode = error; |
| |
| SQLMODULE_ID module; |
| init_SQLMODULE_ID(&module); |
| SQLDESC_ID cond_desc; |
| init_SQLDESC_ID(&cond_desc, SQLCLI_CURRENT_VERSION, desc_handle, |
| &module); |
| |
| // Get the total number of conditions and # of rows affected |
| |
| Int32 total_conds = 0; |
| Int64 rows_affected = 0; |
| |
| SQL_EXEC_AllocDesc(&cond_desc,2); |
| |
| SQL_EXEC_SetDescItem(&cond_desc, 1, SQLDESC_TYPE_FS, |
| REC_BIN32_SIGNED, 0); |
| SQL_EXEC_SetDescItem(&cond_desc, 1, SQLDESC_VAR_PTR, |
| (Long) &total_conds, 0); |
| SQL_EXEC_SetDescItem(&cond_desc, 2, SQLDESC_TYPE_FS, |
| REC_BIN64_SIGNED, 0); |
| SQL_EXEC_SetDescItem(&cond_desc, 2, SQLDESC_VAR_PTR, |
| (Long) &rows_affected, 0); |
| Lng32 stmt_items[2]; |
| stmt_items[0] = SQLDIAG_NUMBER; |
| stmt_items[1] = SQLDIAG_ROW_COUNT; |
| SQL_EXEC_GetDiagnosticsStmtInfo(stmt_items, &cond_desc); |
| |
| // remember # of rows affected in a global variable |
| rowsAffected += rows_affected; |
| |
| // Attach msgtext variable with the output descriptor |
| |
| SQLMODULE_ID module2; |
| init_SQLMODULE_ID(&module2); |
| SQLDESC_ID msg_desc; |
| init_SQLDESC_ID(&msg_desc, SQLCLI_CURRENT_VERSION, desc_handle, |
| &module2); |
| |
| SQLDIAG_COND_INFO_ITEM cond_info_item[4]; |
| short SQLCode; |
| char msgtext[MAX_MSGTEXT_LEN]; |
| char otherbuf[MAX_OTHERBUF_LEN]; |
| NABoolean getCondInfo = log->isVerbose(); |
| NABoolean showSQLSTATE = !!getenv("SHOW_SQLSTATE"); |
| |
| short num_output_entries = 2; |
| if (showSQLSTATE) |
| num_output_entries = 3; |
| // total_conds can be 1 (Executor error) or 2 (Compile error, the second |
| // sqlcode being 8822 "Unable to prepare the stmt"). |
| Lng32 specialErr = |
| (ABS(error) == ABS(sqlci_env->specialError()) && total_conds <= 2) ? |
| ABS(error) : 0; |
| |
| if (specialErr) |
| { |
| ComASSERT(total_conds > 0); |
| total_conds = 1; |
| getCondInfo = TRUE; |
| showSQLSTATE = FALSE; |
| num_output_entries = 3; |
| lastLineWasABlank = TRUE; |
| } |
| |
| SQL_EXEC_AllocDesc(&msg_desc, num_output_entries); |
| |
| // Set up to receive Message text. |
| SQL_EXEC_SetDescItem(&msg_desc, 1, SQLDESC_TYPE_FS, |
| REC_BYTE_F_ASCII, 0); |
| SQL_EXEC_SetDescItem(&msg_desc, 1, SQLDESC_LENGTH, |
| MAX_MSGTEXT_LEN, 0); |
| SQL_EXEC_SetDescItem(&msg_desc, 1, SQLDESC_VAR_PTR, |
| (Long) &msgtext, 0); |
| cond_info_item[0].item_id = SQLDIAG_MSG_TEXT; |
| cond_info_item[0].cond_number_desc_entry = 1; |
| |
| // set up to receive sqlcode |
| SQL_EXEC_SetDescItem(&msg_desc, 2, SQLDESC_TYPE_FS, |
| REC_BIN16_SIGNED, 0); |
| |
| SQL_EXEC_SetDescItem(&msg_desc, 2, SQLDESC_VAR_PTR, |
| (Long) &SQLCode, 0); |
| |
| cond_info_item[1].item_id = SQLDIAG_SQLCODE; |
| cond_info_item[1].cond_number_desc_entry = 2; |
| |
| // |
| if (showSQLSTATE || specialErr) |
| { |
| SQL_EXEC_SetDescItem(&msg_desc, 3, SQLDESC_TYPE_FS, |
| REC_BYTE_F_ASCII, 0); |
| SQL_EXEC_SetDescItem(&msg_desc, 3, SQLDESC_LENGTH, |
| MAX_OTHERBUF_LEN, 0); |
| SQL_EXEC_SetDescItem(&msg_desc, 3, SQLDESC_VAR_PTR, |
| (Long) &otherbuf, 0); |
| cond_info_item[2].item_id = SQLDIAG_RET_SQLSTATE; |
| cond_info_item[2].cond_number_desc_entry = 3; |
| |
| if (specialErr) |
| { |
| // "msgtext" is really cat-name; "otherbuf" will contain schema-name. |
| cond_info_item[0].item_id = SQLDIAG_CATALOG_NAME; |
| cond_info_item[2].item_id = SQLDIAG_SCHEMA_NAME; |
| } |
| } |
| |
| Int32 curr_cond = 1; |
| SQL_EXEC_SetDescEntryCount(&cond_desc, 1); |
| SQL_EXEC_SetDescItem(&cond_desc, 1, SQLDESC_VAR_PTR, |
| (Long) &curr_cond, 0); |
| |
| if (!(error == SQL_Success)) |
| |
| { |
| if (total_conds) |
| { |
| // Start with a blank line -- cf. NADumpDiags(GetErrorMessage.C) |
| if (!lastLineWasABlank) |
| { |
| SQL_EXEC_GetDiagnosticsCondInfo(cond_info_item, |
| &cond_desc, &msg_desc); |
| if ((SQLCode != 100) && |
| ((SQLCode < 0) || (SQLCode > 0 && getCondInfo ))) |
| { |
| if (displayErr) // || (SQLCode > 0)) |
| { |
| log->WriteAll(""); |
| // The error text(s) we are about to emit |
| // each have two lines, |
| // the second of which is a blank. |
| lastLineWasABlank = TRUE; |
| } |
| } |
| } |
| } |
| |
| // Loop through total number of conditions, and print out |
| // the error message text. This loop should emulate |
| // NADumpDiags (GetErrorMessage.C) as much as possible. |
| for (; curr_cond <= total_conds; curr_cond++) |
| { |
| SQL_EXEC_GetDiagnosticsCondInfo(cond_info_item, |
| &cond_desc, &msg_desc); |
| |
| // do not output no data warning 100. |
| // do not output warning message if it's printed during preparation |
| // on Linux. |
| if ((SQLCode == 100) || (SQLCode == prepcode)) |
| { |
| if ((isEOD) && (SQLCode == 100)) // 100: SQL_Eof |
| *isEOD = 1; |
| continue; |
| } |
| |
| //if 'set warnings off' set |
| if ((SQLCode < 0) || (SQLCode > 0 && getCondInfo )) |
| { |
| |
| if (msgtext[0] == '\0') // an empty message |
| { |
| strcpy(msgtext, "*** ERROR[15000] Unexpected Error: Message text missing"); |
| } |
| CharInfo::CharSet TCS = sqlci_env->getTerminalCharset(); |
| CharInfo::CharSet ISOMAPCS = sqlci_env->getIsoMappingCharset(); |
| |
| if( |
| TCS != CharInfo::UTF8/*msgcharset*/ |
| ) |
| { |
| charBuf cbuf((unsigned char*)msgtext, strlen(msgtext)); |
| NAWcharBuf* wcbuf = 0; |
| Int32 errorcode = 0; |
| wcbuf = csetToUnicode(cbuf, 0, wcbuf, CharInfo::UTF8/*msgcharset*/, errorcode); |
| NAString* tempstr; |
| if (errorcode == 0){ |
| tempstr = unicodeToChar(wcbuf->data(),wcbuf->getStrLen(), TCS, NULL, TRUE); |
| TrimNAStringSpace(*tempstr, FALSE, TRUE); // trim trailing blanks |
| strcpy(msgtext, tempstr->data()); |
| } |
| } |
| |
| if (specialErr && sqlci_env->specialHandler()) |
| { |
| sqlci_env->specialHandler()(sqlci_env, error, msgtext, otherbuf); |
| } |
| else |
| { |
| // ## Kludge for "error" 20109. Internationalization problem...! |
| const char *outtext = msgtext; |
| size_t pfxl = strlen("*** ERROR[20109] "); |
| |
| #if defined(USE_WCHAR) |
| if (wcsncmp(msgtext, L"*** ERROR[20109] ", pfxl) == 0) |
| #else |
| if (strncmp(msgtext, "*** ERROR[20109] ", pfxl) == 0) |
| #endif |
| outtext += pfxl; |
| |
| #ifdef USE_WCHAR |
| if (showSQLSTATE) |
| { |
| $$do something here$$ |
| } |
| if (displayErr)// || (SQLCode > 0)) |
| log->WriteAll((NAWchar*)outtext, NAWstrlen((NAWchar*)outtext)); |
| #else // not wide, so don't use NAWxxx |
| // |
| // Rather than returning from the first executable statements in |
| // HandleCLIError, a couple of breakReceived conditional checks are |
| // performed to suppress the outputting of error messages after a |
| // break key was encountered. This allows MXCI to have more control |
| // of issuing (future break processing enhancements) warning and |
| // error messages during break key processing. |
| if (! breakReceived) |
| { |
| if (showSQLSTATE) |
| { |
| if (displayErr)// || (SQLCode > 0)) |
| { |
| log->WriteAllWithoutEOL("*** SQLSTATE: "); |
| log->WriteAll(otherbuf); |
| } |
| } |
| if (displayErr)// || (SQLCode > 0)) |
| log->WriteAll(outtext); |
| |
| if (sqlci_env->specialError() == |
| MXCI_DONOTISSUE_ERRMSGS) |
| { |
| sqlci_env->resetSpecialError(); |
| curr_cond = curr_cond + total_conds; |
| } |
| |
| } // breakReceived |
| #endif |
| // write out a blank line after error message |
| if (! breakReceived) |
| { |
| if (displayErr)// || (SQLCode > 0)) |
| log->WriteAll(""); |
| } // breakReceived |
| } |
| } |
| } // for |
| } |
| |
| if (displayErr)// || (SQLCode > 0)) |
| SqlCmd::clearCLIDiagnostics(); |
| |
| SQL_EXEC_DeallocDesc(&cond_desc); |
| SQL_EXEC_DeallocDesc(&msg_desc); |
| // delete (cond_desc); |
| // delete (msg_desc); |
| } // error != 0 |
| |
| // Check if Ctrl+break occured... nk |
| if ( sqlci_env->diagsArea().mainSQLCODE() == SQLCI_BREAK_RECEIVED) |
| error = SQL_Canceled; |
| |
| } // HandleCLIError |
| |
| |
| void handleLocalError(ComDiagsArea *diags, SqlciEnv *sqlci_env) |
| { |
| Logfile *log = sqlci_env->get_logfile(); |
| |
| // Here the variable worstcode has to be set to SQL_Error in |
| // case of an error and SQL_Warning in case of a warning. |
| // which might have been caused due to a param processing error/warning. |
| // Usually this variable gets set in the HandleCLIError() function, |
| // when HandleCLIError() is called with a error after a CLI call. |
| // Soln :10-021203-3433 |
| |
| if (diags->getNumber(DgSqlCode::ERROR_)) { |
| worstcode = SQL_Error; |
| } |
| else if (diags->getNumber(DgSqlCode::WARNING_)) { |
| worstcode = SQL_Warning; |
| } |
| |
| if (!lastLineWasABlank) log->WriteAllWithoutEOL(""); |
| lastLineWasABlank = TRUE; |
| |
| ostringstream errMsg; |
| NADumpDiags(errMsg, diags, TRUE/*newline*/, 0, NULL, log->isVerbose(), |
| sqlci_env->getTerminalCharset()); |
| |
| errMsg << ends; |
| |
| log->WriteAllWithoutEOL(errMsg.str().c_str()); |
| } |
| |
| Int64 getRowsAffected(SQLSTMT_ID *stmt) |
| { |
| Int32 rc; |
| rc = SQL_EXEC_GetDiagnosticsStmtInfo2(stmt, |
| SQLDIAG_ROW_COUNT, &rowsAffected, |
| NULL, 0, NULL); |
| if (rc == 0) |
| return rowsAffected; |
| else |
| return -1; |
| } |
| |
| Int32 getDiagsCondCount(SQLSTMT_ID *stmt) |
| { |
| Int32 rc; |
| Int32 diagsCondCount; |
| rc = SQL_EXEC_GetDiagnosticsStmtInfo2(stmt, |
| SQLDIAG_NUMBER, &diagsCondCount, |
| NULL, 0, NULL); |
| if (rc >= 0) |
| return diagsCondCount; |
| else |
| return 0; |
| } |
| |
| static char * upshiftStr(char * inStr, char * outStr, UInt32 len) |
| { |
| for (UInt32 i = 0; i < len; i++) |
| { |
| outStr[i] = toupper(inStr[i]); |
| } |
| |
| return outStr; |
| } |
| |
| char * SqlCmd::replacePattern(SqlciEnv * sqlci_env, char * str) |
| { |
| if (str == NULL) |
| return NULL; |
| |
| UInt32 len = strlen(str); |
| |
| char upperStr[20]; |
| // if SET PATTERN or RESET PATTERN, do not replace pattern. |
| UInt32 s = 0; |
| if (len >= strlen("SET PATTERN")) |
| { |
| if (strncmp(upshiftStr(str, upperStr, 3), "SET", 3) == 0) |
| s = 3; |
| } |
| else if (len >= strlen("RESET PATTERN")) |
| { |
| if (strncmp(upshiftStr(str, upperStr, 5), "RESET", 5) == 0) |
| s = 5; |
| } |
| if (s > 0) // SET or RESET found |
| { |
| // skip blanks |
| while ((s <= len) && |
| (str[s] == ' ')) |
| s++; |
| |
| if (s < len) |
| { |
| if ((len - s) >= strlen("PATTERN")) |
| { |
| if (strncmp(upshiftStr(&str[s], upperStr, 7), "PATTERN", 7) == 0) |
| return str; |
| } |
| } |
| } |
| |
| // preprocess the argument and replace the pattern: <definename > |
| // (< and > are included) with the value of define/env-var "definename". |
| enum State { CONSUME_CHAR, QUOTE_SEEN, |
| LPATTERN_SEEN, RPATTERN_SEEN }; |
| |
| UInt32 outstr_len = 500 + len; |
| char * outstr = new char[outstr_len]; |
| char * patternText = new char[100]; |
| |
| UInt32 i = 0; |
| UInt32 j = 0; |
| UInt32 k = 0; |
| NABoolean skipChar = FALSE; |
| NABoolean inSingleQuote = FALSE; |
| State state = CONSUME_CHAR; |
| NABoolean patternSeen = FALSE; |
| while (i <= len) |
| { |
| skipChar = TRUE; |
| switch (state) |
| { |
| case CONSUME_CHAR: |
| if (str[i] == '\'') |
| { |
| state = QUOTE_SEEN; |
| inSingleQuote=TRUE; |
| } |
| if (str[i] == '"') |
| { |
| state = QUOTE_SEEN; |
| inSingleQuote = FALSE; |
| } |
| else if ((str[i] == '$') && ((i+1) < len) && (str[i+1] == '$')) |
| { |
| i+=2; |
| state = LPATTERN_SEEN; |
| skipChar = FALSE; |
| } |
| break; |
| |
| case QUOTE_SEEN: |
| if (str[i] == '\'') |
| { |
| // If in a single quote, make sure this quote is the true end |
| if (inSingleQuote) |
| { |
| // If string contains two single quotes, can skip - not the end |
| if (((i+1) < len) && (str[i+1] == '\'')) |
| { |
| outstr[k] = str[i]; // skip over quote |
| i++; |
| k++; |
| } |
| // The quote mark actually signifies the end of the quote |
| else |
| state = CONSUME_CHAR; |
| } |
| // else: Double quote found, so continue, not the end |
| } |
| |
| if (str[i] == '"') |
| { |
| // If in a double quote, make sure this quote is the true end |
| if (!inSingleQuote) |
| { |
| //If string contains two double quotes, can skip - not the end |
| if (((i+1) < len) && (str[i+1] == '\'')) |
| { |
| outstr[k] = str[i]; // skip over quote |
| i++; |
| k++; |
| } |
| |
| // The double quote mark signifies the end of the quote |
| else |
| state = CONSUME_CHAR; |
| } |
| // else: single quote found, so continue - not the end |
| } |
| break; |
| |
| case LPATTERN_SEEN: |
| patternSeen = TRUE; |
| if ((str[i] == '$') && ((i+1) < len) && (str[i+1] == '$')) |
| { |
| i+=2; |
| state = RPATTERN_SEEN; |
| } |
| else |
| { |
| patternText[j++] = str[i]; |
| i++; |
| } |
| skipChar = FALSE; |
| break; |
| |
| case RPATTERN_SEEN: |
| // find value of pattern and replace |
| patternText[j] = '\0'; |
| Param * pattern |
| = sqlci_env->get_patternlist()->get(patternText); |
| |
| char * patternValue = NULL; |
| if (pattern == NULL) |
| { |
| // if an env var is present with this name, use it |
| patternValue = getenv(patternText); |
| } |
| else |
| { |
| patternValue = pattern->getValue(); |
| } |
| |
| |
| if (patternValue) |
| { |
| strncpy((char *)&outstr[k], patternValue, strlen(patternValue)); |
| k += strlen(patternValue); |
| |
| //special note: the total length of outstr should be smaller |
| //than outstr_len. if the condition below becomes false, |
| //increase outstr_len at the top of the function |
| ComASSERT(k <= outstr_len); |
| } |
| |
| j = 0; |
| skipChar = FALSE; |
| state = CONSUME_CHAR; |
| break; |
| |
| } |
| if (skipChar) |
| { |
| outstr[k] = str[i]; |
| i++; |
| k++; |
| } |
| } // while |
| |
| outstr[k] = '\0'; |
| |
| delete [] patternText; |
| if (NOT patternSeen) |
| { |
| delete [] outstr; |
| return str; |
| } |
| else |
| return outstr; |
| } |
| |
| SqlCmd::SqlCmd(const sql_cmd_type cmd_type_, const char * argument_) |
| : SqlciNode(SqlciNode::SQL_CMD_TYPE), |
| cmd_type(cmd_type_) |
| { |
| if (argument_) |
| { |
| sql_stmt = new char[strlen(argument_)+1]; |
| strcpy(sql_stmt, argument_); |
| } |
| else |
| sql_stmt = 0; |
| } |
| |
| SqlCmd::~SqlCmd() |
| { |
| if (sql_stmt) |
| delete [] sql_stmt; |
| } |
| |
| short SqlCmd::showShape(SqlciEnv *sqlci_env, const char *query) |
| { |
| if ((!query) || |
| (strncmp(query, "SHOWSHAPE", 9) == 0)) |
| return 0; |
| |
| char * buf = new char[strlen("SHOWSHAPE ") + strlen(query) + 1]; |
| strcpy(buf, "SHOWSHAPE "); |
| strcat(buf, query); |
| |
| DML dml(buf, DML_SHOWSHAPE_TYPE, "__SQLCI_DML_SHOWSHAPE__"); |
| |
| short retcode = dml.process(sqlci_env); |
| delete buf; |
| if (retcode) |
| return retcode; |
| |
| return 0; |
| } |
| |
| short SqlCmd::updateRepos(SqlciEnv * sqlci_env, SQLSTMT_ID * stmt, char * queryId) |
| { |
| Lng32 retcode = 0; |
| |
| // get explain fragment. |
| Lng32 explainDataLen = 50000; // start with 50K bytes |
| Int32 retExplainLen = 0; |
| char * explainData = new char[explainDataLen + 1]; |
| retcode = SQL_EXEC_GetExplainData(stmt, |
| explainData, explainDataLen+1, |
| &retExplainLen |
| ); |
| if (retcode == -CLI_GENCODE_BUFFER_TOO_SMALL) |
| { |
| delete explainData; |
| |
| explainDataLen = retExplainLen; |
| explainData = new char[explainDataLen + 1]; |
| |
| SqlCmd::clearCLIDiagnostics(); |
| retcode = SQL_EXEC_GetExplainData(stmt, |
| explainData, explainDataLen+1, |
| &retExplainLen |
| ); |
| } |
| |
| if (retcode < 0) |
| { |
| delete explainData; |
| |
| HandleCLIError(retcode, sqlci_env); |
| |
| return retcode; |
| } |
| |
| explainDataLen = retExplainLen; |
| |
| // update repository |
| ExeCliInterface cliInterface; |
| |
| SQL_EXEC_SetParserFlagsForExSqlComp_Internal(0x20000); |
| |
| char * queryBuf = new char[4000]; |
| |
| Int64 ts = NA_JulianTimestamp(); |
| str_sprintf(queryBuf, "insert into %s.\"%s\".%s (instance_id, tenant_id, host_id, exec_start_utc_ts, query_id, explain_plan) values (0,0,0, CONVERTTIMESTAMP(%ld), '%s', '' ) ", |
| TRAFODION_SYSCAT_LIT, SEABASE_REPOS_SCHEMA, REPOS_METRIC_QUERY_TABLE, |
| ts, queryId); |
| |
| retcode = cliInterface.executeImmediatePrepare(queryBuf); |
| if (retcode < 0) |
| { |
| HandleCLIError(retcode, sqlci_env); |
| |
| goto label_return; |
| } |
| |
| retcode = cliInterface.clearExecFetchClose(explainData, explainDataLen); |
| if (retcode < 0) |
| { |
| HandleCLIError(retcode, sqlci_env); |
| |
| goto label_return; |
| } |
| |
| retcode = SQL_EXEC_StoreExplainData( |
| &ts, queryId, |
| explainData, explainDataLen); |
| if (retcode < 0) |
| { |
| HandleCLIError(retcode, sqlci_env); |
| |
| goto label_return; |
| } |
| |
| label_return: |
| SQL_EXEC_ResetParserFlagsForExSqlComp_Internal(0x20000); |
| |
| delete explainData; |
| delete queryBuf; |
| |
| return retcode; |
| } |
| |
| short SqlCmd::cleanupAfterError(Lng32 retcode, |
| SqlciEnv * sqlci_env, |
| SQLSTMT_ID * stmt, |
| SQLDESC_ID *sql_src, |
| SQLDESC_ID *output_desc, |
| SQLDESC_ID *input_desc, |
| NABoolean resetLastExecStmt) |
| { |
| // if retcode < 0, it is an error. |
| // Clean up and return. |
| if (retcode < 0) |
| { |
| SQL_EXEC_DeallocDesc(input_desc); |
| SQL_EXEC_DeallocDesc(output_desc); |
| SQL_EXEC_DeallocDesc(sql_src); |
| SQL_EXEC_DeallocStmt(stmt); |
| if (global_sqlci_env->getDeallocateStmt()) |
| global_sqlci_env->resetDeallocateStmt(); |
| delete (SQLMODULE_ID*)output_desc->module; |
| delete (SQLMODULE_ID*)input_desc->module; |
| delete (SQLMODULE_ID*)sql_src->module; |
| delete (SQLMODULE_ID*)stmt->module; |
| delete input_desc; |
| delete output_desc; |
| delete sql_src; |
| delete [] stmt->identifier; |
| delete stmt; |
| if (resetLastExecStmt) |
| sqlci_env->lastExecutedStmt() = NULL; |
| |
| SqlCmd::clearCLIDiagnostics(); |
| |
| return (short)SQL_Error; |
| } |
| |
| return 0; |
| } |
| |
| short SqlCmd::do_prepare(SqlciEnv * sqlci_env, |
| PrepStmt * prep_stmt, |
| char * sqlStmt, |
| NABoolean resetLastExecStmt, |
| Lng32 rsIndex, |
| Int32 *prepcode, |
| Lng32 *statisticsType) |
| { |
| if (sqlci_env->showShape()) |
| { |
| showShape(sqlci_env, sqlStmt); |
| } |
| |
| SQLSTMT_ID *stmt = new SQLSTMT_ID; |
| SQLDESC_ID *sql_src = new SQLDESC_ID; |
| SQLDESC_ID *output_desc = new SQLDESC_ID; |
| SQLDESC_ID *input_desc = new SQLDESC_ID; |
| |
| memset (stmt, 0, sizeof(SQLSTMT_ID)); |
| memset (sql_src, 0, sizeof(SQLDESC_ID)); |
| memset (output_desc, 0, sizeof(SQLDESC_ID)); |
| memset (input_desc, 0, sizeof(SQLDESC_ID)); |
| |
| SQLMODULE_ID * module = new SQLMODULE_ID; |
| stmt->module = module; |
| init_SQLMODULE_ID(module); |
| |
| module = new SQLMODULE_ID; |
| sql_src->module = module; |
| init_SQLMODULE_ID(module); |
| |
| module = new SQLMODULE_ID; |
| input_desc->module = module; |
| init_SQLMODULE_ID(module); |
| |
| module = new SQLMODULE_ID; |
| output_desc->module = module; |
| init_SQLMODULE_ID(module); |
| |
| SqlCmd::clearCLIDiagnostics(); |
| |
| Lng32 retcode = 0; |
| |
| // replace any user defined pattern in the sql query |
| // char * str = replacePattern(sqlci_env, sqlStmt); |
| char * str = sqlStmt; |
| |
| prep_stmt->set(str, NULL, stmt, 0, NULL, 0, NULL); |
| |
| char *stmtName = prep_stmt->getStmtName(); |
| |
| // Bookkeeping for stored procedure result sets |
| NABoolean isResultSet = (rsIndex > 0 ? TRUE : FALSE); |
| NABoolean skipPrepare = isResultSet; |
| if (!isResultSet) |
| HandleCLIErrorInit(); |
| |
| /* allocate a statement */ |
| stmt->version = SQLCLI_CURRENT_VERSION; |
| stmt->name_mode = stmt_name; |
| char * identifier = new char[strlen(stmtName) + 1]; |
| stmt->identifier_len = strlen(stmtName); |
| str_cpy_all(identifier,stmtName, stmt->identifier_len); |
| identifier[stmt->identifier_len] = 0; |
| stmt->identifier = identifier; |
| stmt->handle = 0; |
| |
| if (!isResultSet) |
| { |
| retcode = SQL_EXEC_AllocStmt(stmt, 0); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| else |
| { |
| SQLSTMT_ID callStmt; |
| SQLMODULE_ID module; |
| init_SQLMODULE_ID(&module); |
| init_SQLSTMT_ID(&callStmt, SQLCLI_CURRENT_VERSION, stmt_name, &module); |
| |
| char *callStmtName = sqlci_env->lastExecutedStmt()->getStmtName(); |
| callStmt.identifier_len = (Lng32) strlen(callStmtName); |
| callStmt.identifier = callStmtName; |
| |
| retcode = SQL_EXEC_AllocStmtForRS(&callStmt, rsIndex, stmt); |
| |
| // Statement allocation may have failed simply because the RS |
| // index is out of range or because the parent statement is not a |
| // CALL. That can be tolerated and in response we are going to |
| // return early. |
| if (retcode == -8909 || // Parent stmt is not a CALL |
| retcode == -8916) // RS index out of range |
| { |
| SqlCmd::clearCLIDiagnostics(); |
| } |
| else |
| { |
| HandleCLIError(retcode, sqlci_env); |
| } |
| } |
| |
| // Statement allocation failed. If errors needed to be reported to |
| // the console, that has already happened. We can cleanup and |
| // return. |
| if (retcode < 0) |
| { |
| return cleanupAfterError(retcode, sqlci_env, stmt, sql_src, |
| output_desc, input_desc, resetLastExecStmt); |
| } |
| |
| if (!isResultSet) |
| { |
| global_sqlci_env->setDeallocateStmt(); |
| global_sqlci_env->setLastAllcatedStmt(stmt); |
| } |
| |
| /* allocate a descriptor which will hold the sql statement source */ |
| sql_src->version = SQLCLI_CURRENT_VERSION; |
| sql_src->name_mode = desc_handle; |
| sql_src->identifier = 0; |
| sql_src->identifier_len = 0; |
| sql_src->handle = 0; |
| |
| retcode = SQL_EXEC_AllocDesc(sql_src, 1); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_TYPE_FS, |
| REC_BYTE_V_ANSI, 0); |
| retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_CHAR_SET_NAM, |
| 0, (char*)CharInfo::getCharSetName(sqlci_env->getTerminalCharset())); |
| retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_VAR_PTR, (Long)str, 0); |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_LENGTH, strlen(str) + 1, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| SQL_QUERY_COST_INFO queryCostInfo; |
| SQL_QUERY_COMPILER_STATS_INFO queryCompStatsInfo; |
| char uniqueQueryIdBuf[400]; |
| Lng32 uniqueQueryIdLenBuf = 399; |
| |
| char * uniqueQueryIdPtr = uniqueQueryIdBuf; |
| Lng32 * uniqueQueryIdLenPtr = &uniqueQueryIdLenBuf; |
| |
| if (!skipPrepare) |
| { |
| /* prepare it */ |
| // Get cost and set unique query id as well |
| strcpy(uniqueQueryIdBuf, " "); |
| |
| ULng32 prepFlags = 0; |
| if ((stmt->identifier_len > 0) && |
| (strncmp(stmt->identifier, "__SQLCI_DML_", strlen("__SQLCI_DML_")) == 0)) |
| { |
| prepFlags |=PREPARE_STANDALONE_QUERY; |
| |
| } |
| prepFlags |=PREPARE_USE_EMBEDDED_ARKCMP; // mxosrvr needs to set this too. |
| retcode = SQL_EXEC_Prepare2(stmt, sql_src, |
| NULL, 0, NULL, |
| &queryCostInfo, |
| &queryCompStatsInfo, |
| uniqueQueryIdPtr, |
| uniqueQueryIdLenPtr, |
| prepFlags |
| ); |
| |
| // save returned query id in prep_stmt |
| if (prep_stmt->uniqueQueryId()) |
| { |
| delete prep_stmt->uniqueQueryId(); |
| prep_stmt->uniqueQueryIdLen() = 0; |
| } |
| |
| if (*uniqueQueryIdLenPtr > 0) |
| { |
| prep_stmt->uniqueQueryIdLen() = *uniqueQueryIdLenPtr; |
| |
| prep_stmt->uniqueQueryId() = new char[prep_stmt->uniqueQueryIdLen() + 1]; |
| memcpy(prep_stmt->uniqueQueryId(), uniqueQueryIdPtr, |
| prep_stmt->uniqueQueryIdLen()); |
| prep_stmt->uniqueQueryId()[prep_stmt->uniqueQueryIdLen()] = 0; |
| } |
| |
| if (prepcode != NULL) |
| *prepcode = retcode; |
| HandleCLIError(retcode, sqlci_env); |
| |
| // if SQL_EXEC_Prepare returned a value < 0, it is an error. |
| // Clean up and return. |
| if (retcode < 0) |
| { |
| return cleanupAfterError(retcode, sqlci_env, stmt, sql_src, |
| output_desc, input_desc, resetLastExecStmt); |
| } |
| } // if (!skipPrepare) |
| |
| // Statistics Collection Type |
| if (statisticsType != NULL) |
| *statisticsType = queryCompStatsInfo.statsCollectionType; |
| delete (SQLMODULE_ID *)input_desc->module; |
| delete (SQLMODULE_ID *)output_desc->module; |
| input_desc->module = output_desc->module = NULL; |
| |
| // find the statement type |
| if (!skipPrepare) |
| { |
| retcode = SQL_EXEC_GetStmtAttr(stmt, SQL_ATTR_QUERY_TYPE, |
| &prep_stmt->queryType(), |
| NULL, 0, NULL); |
| HandleCLIError(retcode, sqlci_env); |
| Lng32 subqueryType; |
| |
| retcode = SQL_EXEC_GetStmtAttr(stmt, SQL_ATTR_SUBQUERY_TYPE, |
| &subqueryType, NULL, 0, NULL); |
| HandleCLIError(retcode, sqlci_env); |
| prep_stmt->setSubqueryType(subqueryType); |
| } |
| else if (isResultSet) |
| prep_stmt->queryType() = SQL_SP_RESULT_SET; |
| |
| init_SQLDESC_ID(input_desc, SQLCLI_CURRENT_VERSION, desc_handle); |
| init_SQLDESC_ID(output_desc, SQLCLI_CURRENT_VERSION, desc_handle); |
| |
| /* allocate an input descriptor to send values. */ |
| retcode = SQL_EXEC_AllocDesc(input_desc, 500); |
| HandleCLIError(retcode, sqlci_env); |
| |
| /* allocate an output descriptor to retrieve values. */ |
| retcode = SQL_EXEC_AllocDesc(output_desc, 500); |
| HandleCLIError(retcode, sqlci_env); |
| |
| // An undocumented environment variable can be used to select WIDE |
| // descriptors. A WIDE descriptor is only meaningful for a CALL |
| // statement and describes all input and output values together in a |
| // single descriptor. |
| if (getenv("SQLCI_DESCRIBE_WIDE")) |
| { |
| SQL_EXEC_SetDescItem(input_desc, 1, SQLDESC_DESCRIPTOR_TYPE, |
| DESCRIPTOR_TYPE_WIDE, 0); |
| SQL_EXEC_SetDescItem(output_desc, 1, SQLDESC_DESCRIPTOR_TYPE, |
| DESCRIPTOR_TYPE_WIDE, 0); |
| } |
| |
| /* describe the input/output entries into the input/output descriptor */ |
| Lng32 num_input_entries = 0, num_output_entries = 0; |
| retcode = SQL_EXEC_DescribeStmt(stmt, input_desc, output_desc); |
| if (retcode < 0) |
| { |
| // This is a stored procedure result set without a valid query |
| // plan. It could be that we just went beyond the end of the |
| // collection of results for the current CALL statement. That is |
| // OK and is not an error to report to the console. It just means |
| // our result set processing should end so we cleanup and |
| // return. If some other error was encountered, that is unexpected |
| // and we will report it to the user, then cleanup and return. |
| |
| if (isResultSet && retcode == -8915) |
| SqlCmd::clearCLIDiagnostics(); |
| else |
| HandleCLIError(retcode, sqlci_env); |
| |
| SqlCmd::clearCLIDiagnostics(); |
| |
| return cleanupAfterError(retcode, sqlci_env, stmt, sql_src, |
| output_desc, input_desc, resetLastExecStmt); |
| } |
| else if (retcode != 8818) |
| { |
| HandleCLIError(retcode, sqlci_env); |
| } |
| else |
| { |
| SqlCmd::clearCLIDiagnostics(); |
| |
| retcode = SQL_EXEC_GetDescEntryCount(input_desc, &num_input_entries); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_GetDescEntryCount(output_desc, &num_output_entries); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (num_input_entries > 500) |
| { |
| retcode = SQL_EXEC_DeallocDesc(input_desc); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_AllocDesc(input_desc, num_input_entries); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DescribeStmt(stmt, input_desc, NULL); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| if (num_output_entries > 500) |
| { |
| retcode = SQL_EXEC_DeallocDesc(output_desc); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_AllocDesc(output_desc, num_output_entries); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DescribeStmt(stmt, NULL, output_desc); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| } |
| |
| retcode = SQL_EXEC_GetDescEntryCount(input_desc, &num_input_entries); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_GetDescEntryCount(output_desc, &num_output_entries); |
| HandleCLIError(retcode, sqlci_env); |
| if (breakReceived) |
| { |
| delete sql_src; |
| delete input_desc; |
| delete output_desc; |
| return SQL_Canceled; |
| } |
| prep_stmt->set(str, sql_src, stmt, |
| num_input_entries, input_desc, |
| num_output_entries, output_desc); |
| |
| addOutputInfoToPrepStmt(sqlci_env, prep_stmt); |
| |
| if (resetLastExecStmt) |
| { |
| sqlci_env->lastExecutedStmt() = NULL; |
| sqlci_env->lastDmlStmtStatsType() = SQLCLIDEV_NO_STATS; |
| } |
| |
| return 0; |
| } |
| |
| void SqlCmd::addOutputInfoToPrepStmt(SqlciEnv *sqlci_env, |
| PrepStmt *prep_stmt) |
| { |
| if (!prep_stmt) |
| return; |
| |
| Lng32 num_output_entries = prep_stmt->numOutputEntries(); |
| SQLDESC_ID *output_desc = prep_stmt->getOutputDesc(); |
| |
| if (num_output_entries > 0) |
| { |
| Lng32 retcode = 0; |
| |
| // space where actual data is returned |
| char * output_data = 0; |
| Lng32 output_data_len = 0; |
| Lng32 output_buflen = 0; |
| |
| Lng32 datatype = 0; |
| Lng32 length = 0; |
| Lng32 precision = 0; |
| Lng32 scale = 0; |
| Lng32 null_flag = 0; |
| Lng32 charsetEnum = 0; |
| |
| Lng32 curpos = 0; |
| |
| prep_stmt->outputEntries() = new PrepEntry * [num_output_entries]; |
| |
| short entry=1; |
| for (; entry <= num_output_entries; entry++) |
| { |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_TYPE_FS, |
| &datatype, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_OCTET_LENGTH, |
| &length, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (datatype >= REC_MIN_INTERVAL && datatype <= REC_MAX_INTERVAL) { |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_INT_LEAD_PREC, |
| &precision, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_PRECISION, |
| &scale, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| } else if (datatype == REC_DATETIME) { |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_DATETIME_CODE, |
| &precision, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_PRECISION, |
| &scale, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| } else { |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_PRECISION, |
| &precision, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_SCALE, |
| &scale, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (DFS2REC::isAnyCharacter(datatype)) { |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_CHAR_SET, |
| &charsetEnum, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| } |
| |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_NULLABLE, |
| &null_flag, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| char heading[CAT_MAX_HEADING_LEN+1]; |
| Lng32 heading_len; |
| char outputName[CAT_MAX_HEADING_LEN+1]; |
| Lng32 output_name_len; |
| char tableName[CM_GUA_ENAME_LEN+1]; |
| Lng32 table_name_len; |
| |
| ComASSERT(ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN >= |
| (Int32) CAT_MAX_HEADING_LEN); |
| |
| ComASSERT(ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN >= |
| (Int32) CM_GUA_ENAME_LEN); |
| |
| ///////////////////////////////////////////////////////// |
| // If user specified heading is present, display it. |
| // Otherwise display the name of the column or expression |
| // that was used in the select list. |
| ///////////////////////////////////////////////////////// |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_HEADING, |
| 0, heading, |
| CAT_MAX_HEADING_LEN, &heading_len, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_NAME, |
| 0, outputName, |
| CAT_MAX_HEADING_LEN, &output_name_len, 0); |
| |
| if (heading_len == 0) // heading not present. |
| { |
| strncpy(heading, outputName, output_name_len); |
| heading_len = output_name_len; |
| |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_TABLE_NAME, |
| 0, tableName, |
| CM_GUA_ENAME_LEN, &table_name_len, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| Lng32 alignedLen; |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_ALIGNED_LENGTH, |
| &alignedLen, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| output_data_len += alignedLen; |
| |
| if (DFS2REC::isAnyCharacter(datatype)) |
| { |
| Lng32 isCaseInsensitive = 0; |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_CASEINSENSITIVE, |
| &isCaseInsensitive, NULL, |
| 0, NULL, 0); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| // add space to display the returned data. |
| Lng32 out_buflen_this_col = 0; |
| Lng32 display_len = Formatter::display_length( |
| datatype, length, precision, scale, charsetEnum, |
| heading_len, sqlci_env, &out_buflen_this_col); |
| |
| output_buflen += out_buflen_this_col + |
| ((entry < num_output_entries) ? Formatter::BLANK_SEP_WIDTH : 0); |
| |
| prep_stmt->outputEntries()[entry-1] = |
| new PrepEntry(datatype, length, scale, precision, |
| null_flag, |
| heading, heading_len, |
| outputName, output_name_len, display_len, |
| out_buflen_this_col, charsetEnum, tableName, table_name_len); |
| } |
| |
| // allocate space to hold the returned data |
| output_data = new char[output_data_len]; |
| |
| // set var_ptr and ind_ptr |
| curpos = 0; |
| for (entry=1; entry <= num_output_entries; entry++) |
| { |
| PrepEntry * outputEntry = prep_stmt->outputEntries()[entry-1]; |
| |
| Lng32 dataOffset; |
| Lng32 nullIndOffset; |
| |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_NULL_IND_OFFSET, |
| &nullIndOffset, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_DATA_OFFSET, |
| &dataOffset, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (nullIndOffset >= 0) |
| { |
| retcode = SQL_EXEC_SetDescItem(output_desc, entry, |
| SQLDESC_IND_PTR, |
| (Long)&output_data[nullIndOffset],0); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| retcode = SQL_EXEC_SetDescItem(output_desc, entry, |
| SQLDESC_VAR_PTR, |
| (Long)&output_data[dataOffset],0); |
| |
| } |
| |
| prep_stmt->outputDatalen() = output_data_len; |
| prep_stmt->outputData() = output_data; |
| |
| // Allocate space to hold the formatted row that will be displayed. |
| // The 'extraOutputBuf' multiplier is used ONLY for the |
| // buffer allocation itself and NOT for the recorded length |
| // (otherwise, headers get screwed up!). |
| // It is calculated ONLY the first several PREPAREs in SQLCI, |
| // so as to minimize its overhead -- |
| // a getenv of SQL_MXCI_SHOW_NONPRINTING. |
| |
| static Int32 prepCnt = 0; |
| static Lng32 extraOutputBuf; |
| |
| if (prepCnt < 5) { |
| prepCnt++; |
| if (Formatter::getShowNonprintingReplacementChar(TRUE) == |
| Formatter::HEX_EXPANSION_ON) |
| extraOutputBuf = Formatter::HEX_BUFSIZ_MULTIPLIER; |
| else |
| extraOutputBuf = 1; |
| } |
| prep_stmt->outputBuflen() = output_buflen; |
| prep_stmt->outputBuf() = new char[extraOutputBuf * output_buflen + 1]; |
| |
| } // if (num_output_entries > 0) |
| |
| } |
| |
| short SqlCmd::doDescribeInput(SqlciEnv * sqlci_env, |
| SQLSTMT_ID * stmt, |
| PrepStmt * prep_stmt, |
| Lng32 num_input_entries, |
| Int32 numUnnamedParams, |
| char ** unnamedParamArray, |
| CharInfo::CharSet* unnamedParamCharSetArray) |
| { |
| Lng32 retcode = 0; |
| Int32 num_named_params = 0; |
| SqlciList<Param> *unnamed_param_list = NULL; |
| ComDiagsArea *diags = NULL; |
| |
| SQLDESC_ID * input_desc = prep_stmt->getInputDesc(); |
| |
| char * aligned_input_data = 0; |
| Lng32 aligned_input_data_len = 0; |
| NABoolean canAlign = TRUE; |
| |
| // if input params present, then assign their values to the dataptr |
| // field of the descriptor. |
| if (num_input_entries > 0) |
| { |
| short datatype; |
| Lng32 returned_len; |
| Lng32 length = 0; |
| Lng32 precision; |
| Lng32 scale; |
| Lng32 unnamed; |
| Lng32 vcIndLen = -1; |
| CharInfo::CharSet charset = CharInfo::CHARSET_MIN; |
| |
| char param_name[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1]; |
| |
| prep_stmt->inputEntries() = new PrepEntry * [num_input_entries]; |
| |
| for (short entry=1; entry <= num_input_entries; entry++) |
| { |
| Lng32 temp; |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_TYPE_FS, |
| &temp, 0, 0, 0, 0); |
| datatype = (short) temp; |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_OCTET_LENGTH, |
| &length, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| Lng32 alignedLen = 0; |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_ALIGNED_LENGTH, |
| &alignedLen, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| aligned_input_data_len += alignedLen; |
| |
| // check if parameter is unnamed |
| // note: not implemented in executor yet |
| // if parameter is unnamed, SQLDESC_UNNAMED = 1 |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_UNNAMED, |
| &unnamed, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| Lng32 whatToPutIntoPrecision = SQLDESC_PRECISION; |
| Lng32 whatToPutIntoScale = SQLDESC_SCALE; |
| if (datatype >= REC_MIN_INTERVAL && datatype <= REC_MAX_INTERVAL) { |
| whatToPutIntoPrecision = SQLDESC_INT_LEAD_PREC; |
| whatToPutIntoScale = SQLDESC_PRECISION; |
| } else if (datatype == REC_DATETIME) { |
| whatToPutIntoPrecision = SQLDESC_DATETIME_CODE; |
| whatToPutIntoScale = SQLDESC_PRECISION; |
| } else if ( DFS2REC::isAnyCharacter(datatype) ) { |
| |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_CHAR_SET, |
| &temp, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| charset = (CharInfo::CharSet)temp; |
| |
| if ( DFS2REC::isSQLVarChar(datatype)) |
| { |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_VC_IND_LENGTH, |
| &vcIndLen, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| } |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| whatToPutIntoPrecision, |
| &precision, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| whatToPutIntoScale, |
| &scale, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_NAME, |
| 0, param_name, |
| ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN, |
| &returned_len, 0); |
| HandleCLIError(retcode, sqlci_env); |
| param_name[returned_len] = 0; |
| |
| // kludge: until executor recognizes unnamed parameters, |
| // if length of parameter name is zero, parameter is unnamed |
| NABoolean isUnnamed = !returned_len; |
| |
| Param *param = NULL; |
| |
| if (!isUnnamed) { |
| num_named_params++; |
| |
| // lookup this param in the sqlci param-list |
| param = sqlci_env->get_paramlist()->get(param_name); |
| } |
| else if (isUnnamed) { |
| short entryOffset = entry - num_named_params; |
| sprintf(param_name, "(UNNAMED_%hd)", entryOffset); |
| if (numUnnamedParams > 0) { |
| if (entryOffset <= numUnnamedParams) { |
| |
| if ( unnamedParamCharSetArray ) { |
| if ( unnamedParamCharSetArray[entryOffset-1] == CharInfo::UNICODE ) { |
| |
| Int32 len = (Int32)strlen(unnamedParamArray[entryOffset-1]); |
| NAWchar* wstrBuf = new NAWchar[len+1]; |
| |
| LocaleStringToUnicode(sqlci_env->getTerminalCharset(), |
| unnamedParamArray[entryOffset-1], len, |
| wstrBuf, len+1, TRUE); |
| |
| param = new Param(param_name, wstrBuf, CharInfo::UNICODE); |
| |
| delete [] wstrBuf; |
| } else { |
| param = new Param(param_name, |
| unnamedParamArray[entryOffset-1], |
| unnamedParamCharSetArray[entryOffset-1]); |
| } |
| } else |
| param = new Param(param_name, |
| unnamedParamArray[entryOffset-1]); |
| |
| // If it we do a new Param() above that means that |
| // it is an unnamed param and we have to add it to a |
| // list which will then be deallocated later. This is |
| // for Soln 10-031203-1717. |
| if (! unnamed_param_list) |
| unnamed_param_list = new SqlciList<Param>; |
| unnamed_param_list->append(param); |
| //the parameter value is NULL, so set the nullValue_ field |
| //in the param |
| if (!param->getValue()) |
| param->makeNull(); |
| } // unnamed param found in Execute's USING list |
| } |
| } // isUnnamed |
| |
| if (param) |
| { |
| if (param->isNull()) { |
| retcode = SQL_EXEC_SetDescItem(input_desc, entry, |
| SQLDESC_IND_PTR, |
| (Long)(param->getNullValue()), |
| 0); |
| } |
| else { |
| NABoolean error = FALSE; |
| |
| Lng32 inLength = length; |
| |
| Int32 previousEntry = 0; |
| |
| if (diags != NULL) |
| previousEntry = diags->getNumber(DgSqlCode::ERROR_); |
| |
| if ( DFS2REC::isAnyCharacter(datatype) ) |
| scale = (Lng32)charset; // pass in target charset in argument 'scale' |
| |
| retcode = param->convertValue(sqlci_env, datatype, length, |
| precision, scale, vcIndLen, diags); |
| Int32 newestEntry = 0; |
| if (diags != NULL) |
| newestEntry = diags->getNumber(DgSqlCode::ERROR_); |
| |
| //if the convertValue gets a string overflow warning, convert |
| //it to error for non characters and it remains warning for characters |
| if (newestEntry > previousEntry) { |
| if (diags->getErrorEntry(newestEntry)->getSQLCODE() == EXE_STRING_OVERFLOW ){ |
| if (!DFS2REC::isAnyCharacter(datatype)) { |
| diags->negateCondition(newestEntry-1); |
| error = TRUE; |
| } |
| } |
| } |
| |
| // If convertValue did not return any errors continue on this path |
| if ((retcode >= 0) && !error) { |
| if (length != inLength){ |
| // the length of input is different than what cli |
| // returned. Change the length in the descriptor. |
| retcode = SQL_EXEC_SetDescItem(input_desc, entry, |
| SQLDESC_LENGTH, |
| length, |
| 0); |
| |
| canAlign = FALSE; |
| } |
| |
| retcode = SQL_EXEC_SetDescItem(input_desc, entry, |
| SQLDESC_VAR_PTR, |
| (Long)(param->getConvertedValue()), |
| 0); |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_SetDescItem(input_desc, entry, |
| SQLDESC_IND_PTR, |
| 0, 0); |
| } |
| // If convertValue failed and DID return an error the retcode |
| // will be < 0 and it will follow this code path. |
| else { |
| char tgttype[100]; |
| Lng32 charSet; |
| Lng32 collation; |
| |
| retcode = SQL_EXEC_GetDescItem( input_desc |
| , entry |
| , SQLDESC_CHAR_SET |
| ,&charSet |
| , 0 |
| , 0 |
| , 0 |
| , 0 |
| ); |
| HandleCLIError(retcode, sqlci_env); |
| retcode = SQL_EXEC_GetDescItem( input_desc |
| , entry |
| , SQLDESC_COLLATION |
| ,&collation |
| , 0 |
| , 0 |
| , 0 |
| , 0 |
| ); |
| |
| rec_datetime_field dtStartField = REC_DATE_YEAR; |
| rec_datetime_field dtEndField = REC_DATE_SECOND; |
| Lng32 intLeadPrec = SQLInterval::DEFAULT_LEADING_PRECISION; |
| if (datatype == REC_DATETIME) |
| { |
| Lng32 dtCode; |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_DATETIME_CODE, |
| &dtCode, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| // this will get fractional precision |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_PRECISION, |
| &precision, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (dtCode == REC_DTCODE_DATE) |
| { |
| dtStartField = REC_DATE_YEAR; |
| dtEndField = REC_DATE_DAY; |
| } |
| else if (dtCode == REC_DTCODE_TIME) |
| { |
| dtStartField = REC_DATE_HOUR; |
| dtEndField = REC_DATE_SECOND; |
| } |
| else if (dtCode == REC_DTCODE_TIMESTAMP) |
| { |
| dtStartField = REC_DATE_YEAR; |
| dtEndField = REC_DATE_SECOND; |
| } |
| } |
| else if (DFS2REC::isInterval(datatype)) |
| { |
| getIntervalFields(datatype, dtStartField, dtEndField); |
| |
| // this will get fractional precision |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_PRECISION, |
| &precision, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| // this will get interval leading precision |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_INT_LEAD_PREC, |
| &intLeadPrec, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| NAType::convertTypeToText(tgttype, |
| datatype, length, precision, scale, |
| dtStartField, dtEndField, |
| (short)precision, |
| (short)intLeadPrec, |
| FALSE/*upshift*/, |
| FALSE/*caseinsensitive*/, |
| (CharInfo::CharSet) charSet, |
| (CharInfo::Collation) collation, |
| NULL); // displaydatatype |
| |
| // All PARAMS are character type. |
| // #We should single-quote it and double-up any embedded quotes |
| // #Should be a global func (in NAString.cpp?) for this |
| NAString srcval(param->getDisplayValue(sqlci_env->getTerminalCharset())); |
| if (srcval.isNull()) srcval = "''"; // empty string literal |
| |
| if (diags == NULL) |
| diags = ComDiagsArea::allocate(&sqlci_Heap); |
| *diags << DgSqlCode(-SQLCI_PARAM_BAD_CONVERT) |
| << DgString0(Param::getExternalName(param_name)) |
| << DgString1(srcval) |
| << DgString2(tgttype); |
| } // convertValue failed |
| } // not null param |
| } // if param |
| else { |
| if (diags == NULL) |
| diags = ComDiagsArea::allocate(&sqlci_Heap); |
| *diags << DgSqlCode(-SQLCI_PARAM_NOT_FOUND) |
| << DgString0(Param::getExternalName(param_name)); |
| } |
| |
| HandleCLIError(retcode, sqlci_env); |
| |
| prep_stmt->inputEntries()[entry-1] = |
| new PrepEntry(datatype, length, scale, precision, |
| (param ? param->isNull() : 0), // null_flag, |
| NULL, 0, |
| param_name, returned_len, |
| 0, 0, 0, NULL, 0); |
| if (param) |
| { |
| if (param->isNull()) |
| prep_stmt->inputEntries()[entry-1]->setIndPtr( |
| param->getNullValue()); |
| prep_stmt->inputEntries()[entry-1]->setVarPtr( |
| param->getConvertedValue()); |
| } |
| |
| } // for num_input_entries |
| |
| } // if num_input_entries |
| |
| if (numUnnamedParams > 0 && |
| numUnnamedParams > num_input_entries - num_named_params) |
| { |
| if (diags == NULL) |
| diags = ComDiagsArea::allocate(&sqlci_Heap); |
| // Warning only, so continue processing after this! |
| *diags << DgSqlCode(+SQLCI_EXTRA_PARAMS_SUPPLIED) // + (i.e. warning) |
| << DgInt0(numUnnamedParams) |
| << DgInt1(num_input_entries - num_named_params); |
| } |
| |
| if (diags != NULL) |
| { |
| handleLocalError(diags, sqlci_env); |
| if (diags->getNumber(DgSqlCode::ERROR_)) { |
| return SQL_Error; |
| } |
| } |
| |
| if ((num_input_entries > 0) && (canAlign)) |
| { |
| Lng32 dataOffset = -1; |
| Lng32 nullIndOffset = -1; |
| |
| aligned_input_data = new char[aligned_input_data_len]; |
| for (short entry=1; entry <= num_input_entries; entry++) |
| { |
| PrepEntry * inputEntry = prep_stmt->inputEntries()[entry-1]; |
| |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_NULL_IND_OFFSET, |
| &nullIndOffset, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_GetDescItem(input_desc, entry, |
| SQLDESC_DATA_OFFSET, |
| &dataOffset, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (nullIndOffset >= 0) |
| { |
| retcode = SQL_EXEC_SetDescItem(input_desc, entry, |
| SQLDESC_IND_PTR, |
| (Long)&aligned_input_data[nullIndOffset],0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (inputEntry->indPtr()) |
| str_cpy_all(&aligned_input_data[nullIndOffset], |
| inputEntry->indPtr(), sizeof(short)); |
| else |
| { |
| short noNull = 0; |
| str_cpy_all(&aligned_input_data[nullIndOffset], |
| (char*)&noNull, sizeof(short)); |
| } |
| } |
| |
| retcode = SQL_EXEC_SetDescItem(input_desc, entry, |
| SQLDESC_VAR_PTR, |
| (Long)&aligned_input_data[dataOffset],0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (inputEntry->varPtr()) |
| { |
| if (DFS2REC::isAnyVarChar(inputEntry->datatype())) |
| str_cpy_all(&aligned_input_data[dataOffset], |
| inputEntry->varPtr(), |
| sizeof(short) + inputEntry->length()); |
| else |
| str_cpy_all(&aligned_input_data[dataOffset], |
| inputEntry->varPtr(), inputEntry->length()); |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| short SqlCmd::doExec(SqlciEnv * sqlci_env, |
| SQLSTMT_ID * stmt, |
| PrepStmt * prep_stmt, |
| Int32 numUnnamedParams, |
| char ** unnamedParamArray, |
| CharInfo::CharSet* unnamedParamCharSetArray, |
| NABoolean handleError) |
| { |
| Lng32 retcode = 0; |
| rowsAffected = 0; |
| SqlciList<Param> *unnamed_param_list = NULL; |
| |
| SQLDESC_ID * input_desc = prep_stmt->getInputDesc(); |
| SQLDESC_ID * output_desc = prep_stmt->getOutputDesc(); |
| dml_type stmt_type = prep_stmt->getType(); |
| |
| Lng32 num_input_entries = prep_stmt->numInputEntries(); |
| |
| retcode = doDescribeInput(sqlci_env, stmt, prep_stmt, |
| num_input_entries, |
| numUnnamedParams, unnamedParamArray, |
| unnamedParamCharSetArray); |
| if (retcode == SQL_Error) |
| return (short)retcode; |
| |
| /* execute the statement */ |
| retcode = SQL_EXEC_Exec(stmt, input_desc, 0, |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); |
| if (handleError) |
| HandleCLIError(retcode, sqlci_env, TRUE); |
| |
| if (unnamed_param_list) |
| delete unnamed_param_list; |
| |
| if (retcode > 0) |
| getRowsAffected(stmt); |
| return (short)retcode; |
| } // SqlCmd::doExec |
| |
| short SqlCmd::doFetch(SqlciEnv * sqlci_env, SQLSTMT_ID * stmt, |
| PrepStmt * prep_stmt, |
| NABoolean firstFetch, |
| NABoolean handleError, |
| Int32 prepcode) |
| { |
| Lng32 retcode = 0; |
| |
| // fetch rows till EOF. Note, for statements which do not |
| // return rows (like, INSERT...), an EOF will be returned |
| // on the first fetch. |
| retcode = SQL_EXEC_Fetch(stmt, prep_stmt->getOutputDesc(), 0, |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); |
| |
| NABoolean isEOD = 0; |
| if (handleError) |
| HandleCLIError(stmt, retcode, sqlci_env, TRUE, &isEOD,prepcode); |
| if (isEOD) |
| retcode = SQL_Eof; |
| |
| |
| return (short)retcode; |
| } |
| |
| short SqlCmd::doClearExecFetchClose(SqlciEnv * sqlci_env, |
| SQLSTMT_ID * stmt, |
| PrepStmt * prep_stmt, |
| Int32 numUnnamedParams, |
| char ** unnamedParamArray, |
| CharInfo::CharSet* unnamedParamCharSetArray, |
| NABoolean handleError) |
| { |
| Lng32 retcode = 0; |
| rowsAffected = 0; |
| |
| Lng32 num_input_entries = prep_stmt->numInputEntries(); |
| retcode = doDescribeInput(sqlci_env, stmt, prep_stmt, |
| num_input_entries, |
| numUnnamedParams, unnamedParamArray, |
| unnamedParamCharSetArray); |
| if (retcode == SQL_Error) |
| return (short)retcode; |
| |
| retcode = SQL_EXEC_ClearExecFetchClose( |
| stmt, |
| ((prep_stmt->numInputEntries() > 0) |
| ? prep_stmt->getInputDesc() : NULL), |
| ((prep_stmt->numOutputEntries() > 0) |
| ? prep_stmt->getOutputDesc() : NULL), |
| 0, 0, 0); |
| |
| Lng32 queryType = prep_stmt->queryType(); |
| if (queryType != SQL_SELECT_UNIQUE) |
| { |
| if (retcode == SQL_Success) |
| retcode = SQL_Eof; |
| } |
| if (handleError) |
| HandleCLIError(retcode, sqlci_env, TRUE); |
| |
| if (retcode > 0) |
| getRowsAffected(stmt); |
| return (short)retcode; |
| } |
| |
| short SqlCmd::getHeadingInfo(SqlciEnv * sqlci_env, |
| PrepStmt * prep_stmt, |
| char * heading_row, |
| char * underline) |
| { |
| Lng32 retcode = 0; |
| SQLDESC_ID * output_desc = prep_stmt->getOutputDesc(); |
| Lng32 output_buflen = prep_stmt->outputBuflen(); |
| char * heading = new char[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1]; |
| Lng32 returned_len; |
| Lng32 heading_len; |
| Lng32 curpos = 0; |
| |
| str_pad(heading_row, output_buflen, ' '); |
| str_pad(underline, output_buflen, ' '); |
| |
| Lng32 num_output_entries = prep_stmt->numOutputEntries(); |
| for (short entry=1; entry <= num_output_entries; entry++) |
| { |
| ///////////////////////////////////////////////////////// |
| // If user specified heading is present, display it. |
| // Otherwise display the name of the column or expression |
| // that was used in the select list. |
| ///////////////////////////////////////////////////////// |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_HEADING, |
| 0, heading, |
| CAT_MAX_HEADING_LEN, &returned_len, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (returned_len == 0) // heading not present. |
| { |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_NAME, |
| 0, heading, |
| CAT_MAX_HEADING_LEN, &returned_len, 0); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| heading[returned_len] = 0; |
| |
| heading_len = prep_stmt->outputEntries()[entry-1]->displayLen(); |
| str_pad(&underline[curpos], (Int32)heading_len, '-'); |
| |
| str_cpy_all(&heading_row[curpos], heading, returned_len); |
| curpos += heading_len + |
| ((entry < num_output_entries) ? Formatter::BLANK_SEP_WIDTH : 0); |
| |
| } // for |
| heading_row[curpos] = 0; |
| underline[curpos] = 0; |
| |
| // For long headings, trim trailing spaces |
| if (curpos > 72) |
| while (curpos-- && heading_row[curpos] == ' ') |
| heading_row[curpos] = 0; |
| |
| delete [] heading; |
| |
| return 0; |
| } |
| short SqlCmd::displayHeading(SqlciEnv * sqlci_env, |
| PrepStmt * prep_stmt) |
| { |
| Lng32 retcode = 0; |
| |
| Logfile *log = sqlci_env->get_logfile(); |
| if (!lastLineWasABlank) log->WriteAll(""); |
| |
| if (prep_stmt->getType() != DML_DISPLAY_NO_HEADING_TYPE) |
| { |
| // Only obtain and display header row if requested |
| Lng32 output_buflen = prep_stmt->outputBuflen(); |
| char * heading_row = new char[output_buflen + 1]; |
| char * underline = new char[output_buflen + 1]; |
| |
| retcode = getHeadingInfo(sqlci_env, prep_stmt, heading_row, underline); |
| |
| if (sqlci_env->getTerminalCharset() != CharInfo::UTF8) |
| { |
| char * converted_heading_row = new char[output_buflen*4+1]; |
| char *pFirstUntranslatedChar = NULL; |
| UInt32 outLen = 0; |
| UInt32 translatedCharCount = 0; |
| Int32 retCode = UTF8ToLocale ( cnv_version1 |
| , (const char*) heading_row |
| , (const Int32) strlen(heading_row) |
| , (const char*) converted_heading_row |
| , (const Int32) output_buflen*4+1 |
| , (cnv_charset) convertCharsetEnum((Int32)sqlci_env->getTerminalCharset()) |
| , (char* &) pFirstUntranslatedChar |
| , (UInt32 *) &outLen // unsigned int *output_data_len_p |
| , (const Int32) TRUE // const int addNullAtEnd_flag |
| , (const Int32) TRUE // const int allow_invalids |
| , (UInt32 *) &translatedCharCount // unsigned int * translated_char_cnt_p |
| , (const char*) NULL // const char *substitution_char_p |
| ); |
| log->WriteAll(converted_heading_row); |
| delete [] converted_heading_row; |
| } |
| else |
| log->WriteAll(heading_row); |
| |
| log->WriteAll(underline); |
| log->WriteAll(""); |
| |
| delete [] heading_row; |
| delete [] underline; |
| } |
| lastLineWasABlank = TRUE; |
| |
| return 0; |
| } |
| |
| Lng32 SqlCmd::displayRow(SqlciEnv * sqlci_env, |
| PrepStmt * prep_stmt) |
| { |
| NABoolean playItSafeUseTheOldWay = TRUE; |
| |
| Lng32 retcode = 0; |
| char * buf = prep_stmt->outputBuf(); |
| SQLDESC_ID * output_desc = prep_stmt->getOutputDesc(); |
| |
| /* print the output */ |
| Lng32 curpos = 0; |
| |
| Lng32 num_output_entries = prep_stmt->numOutputEntries(); |
| |
| if (playItSafeUseTheOldWay) |
| for (short entry=1; entry <= num_output_entries; entry++) |
| { |
| Long data_addr; |
| Long ind_data_addr; |
| |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_VAR_PTR, |
| &data_addr, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_GetDescItem(output_desc, entry, |
| SQLDESC_IND_PTR, |
| &ind_data_addr, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| PrepEntry * outputEntry = prep_stmt->outputEntries()[entry-1]; |
| Formatter::buffer_it(sqlci_env, (char *)data_addr, |
| outputEntry->datatype(), |
| outputEntry->length(), |
| outputEntry->precision(), |
| outputEntry->scale(), |
| (char *)ind_data_addr, |
| outputEntry->displayLen(), |
| outputEntry->displayBufLen(), |
| outputEntry->nullFlag(), |
| &buf[curpos], &curpos, |
| entry < num_output_entries, //separatorNeeded |
| TRUE); //checkShowNonPrinting |
| } |
| |
| if (buf) |
| buf[curpos] = 0; |
| |
| return curpos; |
| } |
| |
| short SqlCmd::do_execute(SqlciEnv * sqlci_env, |
| PrepStmt * prep_stmt, |
| Int32 numUnnamedParams, |
| char ** unnamedParamArray, |
| CharInfo::CharSet* unnamedParamCharSetArray, |
| Int32 prepcode) |
| { |
| Lng32 retcode = 0; |
| //short ret; |
| Logfile *log = sqlci_env->get_logfile(); |
| SQLSTMT_ID * stmt = prep_stmt->getStmt(); |
| dml_type stmt_type = prep_stmt->getType(); |
| ULng32 num_rows_returned = 0; |
| ULng32 listcount = sqlci_env->getListCount(); |
| NABoolean listcountReached = ((listcount == 0) ? TRUE : FALSE); |
| NABoolean noScreenOutput = (getenv("NO_SCREEN_OUTPUT") ? TRUE : FALSE); |
| NABoolean displayFirstRow = (getenv("DISPLAY_FIRST_ROW") ? TRUE : FALSE); |
| Int32 useCout = 0; // Flag which tells LOG::WRITEALL to use COUT |
| // versus COUT.WRITE. |
| |
| // Bookkeeping for stored procedure result sets |
| NABoolean isResultSet = (stmt_type == DML_CALL_STMT_RS_TYPE ? TRUE : FALSE); |
| char childQueryId[ComSqlId::MAX_QUERY_ID_LEN+1]; |
| Lng32 childQueryIdLen; |
| SQL_QUERY_COST_INFO childQueryCostInfo; |
| SQL_QUERY_COMPILER_STATS_INFO childQueryCompilerStatsInfo; |
| |
| Lng32 queryType = prep_stmt->queryType(); |
| Lng32 subqueryType = prep_stmt->getSubqueryType(); |
| |
| if ((stmt_type == DML_CONTROL_TYPE) && |
| ((prep_stmt->queryType() == SQL_SELECT_NON_UNIQUE) || |
| (prep_stmt->queryType() == SQL_SELECT_UNIQUE))) |
| stmt_type = DML_SELECT_TYPE; |
| else if ((stmt_type == DML_DDL_TYPE) && |
| (prep_stmt->queryType() == SQL_INSERT_NON_UNIQUE)) |
| stmt_type = DML_INSERT_TYPE; |
| else if ((stmt_type == DML_DDL_TYPE) && |
| ((prep_stmt->queryType() == SQL_SELECT_NON_UNIQUE) || |
| (prep_stmt->queryType() == SQL_SELECT_UNIQUE))) |
| stmt_type = DML_SELECT_TYPE; |
| else if ((stmt_type == DML_DDL_TYPE) && |
| (queryType == SQL_EXE_UTIL && subqueryType == SQL_STMT_CTAS)) |
| stmt_type = DML_INSERT_TYPE; |
| |
| |
| NABoolean firstRowDisplayed = FALSE; |
| |
| sqlci_env->lastExecutedStmt() = prep_stmt; |
| |
| |
| NABoolean doCEFC = FALSE; // do ClearExecFetchClose |
| NABoolean doCTAS = FALSE; |
| NABoolean doHBL = FALSE; |
| if (((queryType != SQL_OTHER) && |
| (queryType != SQL_UNKNOWN) && |
| (queryType != SQL_CAT_UTIL) && |
| (queryType != SQL_EXE_UTIL) && |
| (queryType != SQL_SELECT_NON_UNIQUE) && |
| // (queryType != SQL_SELECT_UNIQUE) && |
| (queryType != SQL_CALL_NO_RESULT_SETS) && |
| (queryType != SQL_CALL_WITH_RESULT_SETS) && |
| (! isResultSet) && |
| // (prep_stmt->numOutputEntries() == 0) && |
| (! getenv("NO_MXCI_CEFC"))) && |
| ((queryType == SQL_SELECT_UNIQUE) || |
| (prep_stmt->numOutputEntries() == 0))) |
| { |
| doCEFC = TRUE; |
| retcode = |
| doClearExecFetchClose(sqlci_env, |
| prep_stmt->getStmt(), |
| prep_stmt, |
| numUnnamedParams, |
| unnamedParamArray, |
| unnamedParamCharSetArray, |
| TRUE); |
| } |
| if (queryType == SQL_EXE_UTIL && subqueryType == SQL_STMT_CTAS) |
| doCTAS = TRUE; |
| if (doCTAS) |
| { |
| noScreenOutput = TRUE; |
| if (getenv("DISPLAY_CTAS_OUTPUT")) |
| noScreenOutput = FALSE; |
| } |
| |
| if (queryType == SQL_EXE_UTIL && |
| (subqueryType == SQL_STMT_HBASE_LOAD || subqueryType == SQL_STMT_HBASE_UNLOAD)) |
| doHBL = TRUE; |
| |
| if (NOT doCEFC) |
| { |
| retcode = doExec(sqlci_env, |
| prep_stmt->getStmt(), |
| prep_stmt, |
| numUnnamedParams, |
| unnamedParamArray, |
| unnamedParamCharSetArray, |
| TRUE); |
| |
| } |
| |
| NABoolean processedCallWithResultSets = FALSE; |
| |
| NABoolean firstFetchDone = FALSE; |
| if (retcode >= 0) |
| { |
| // Fetch the first row |
| if ((NOT doCEFC) && Succ_or_Warn) |
| { |
| retcode = doFetch(sqlci_env, prep_stmt->getStmt(), prep_stmt, |
| TRUE, TRUE,prepcode); |
| if (Succ_or_Warn) |
| firstFetchDone = TRUE; |
| } |
| |
| // if first row and output entries, print heading. |
| // don't display heading if DESCRIBE or internal SHOWSHAPE command. |
| if (Succ_or_Warn && prep_stmt->numOutputEntries() > 0) |
| { |
| if (stmt_type != DML_DESCRIBE_TYPE && |
| stmt_type != DML_SHOWSHAPE_TYPE && |
| stmt_type != DML_DISPLAY_NO_ROWS_TYPE && |
| NOT doCTAS && |
| NOT doHBL) |
| displayHeading(sqlci_env, prep_stmt); |
| } |
| |
| // We just fetched the first row. Each iteration of the following |
| // WHILE loop processes one row and then fetches the next. |
| while (Succ_or_Warn && !listcountReached && !processedCallWithResultSets) |
| { |
| num_rows_returned++; |
| if (prep_stmt->numOutputEntries() > 0) |
| { |
| Lng32 curpos = displayRow(sqlci_env, prep_stmt); |
| |
| // Trim trailing spaces from SHOWDDL and INVOKE ``column'' values, |
| // and GET RELATED NAMES OF .../ GET VERSION OF ... |
| // which are really specially formatted variable-length text |
| // (See CmpDescribe.C). |
| if (stmt_type == DML_DESCRIBE_TYPE || |
| stmt_type == DML_SHOWSHAPE_TYPE || |
| stmt_type == DML_DISPLAY_NO_ROWS_TYPE || |
| stmt_type == DML_DISPLAY_NO_HEADING_TYPE || |
| (doCTAS && NOT noScreenOutput) || |
| (doHBL && NOT noScreenOutput)) |
| { |
| useCout = -1; // use COUT for output versus using COUT.WRITE. |
| |
| // Move curpos backwards from the end of the string to |
| // the position of the first non-space character |
| while (curpos > 0 && prep_stmt->outputBuf()[curpos - 1] == ' ') |
| curpos--; |
| |
| // We want to convert a newline-only string ("\n") to |
| // an empty string ("") |
| if (curpos == 1 && prep_stmt->outputBuf()[0] == '\n') |
| curpos--; |
| |
| // Inject a null terminator |
| prep_stmt->outputBuf()[curpos] = 0; |
| } |
| |
| if (! noScreenOutput) |
| log->WriteAll(prep_stmt->outputBuf(),curpos,useCout); |
| else if ((displayFirstRow) && |
| (NOT firstRowDisplayed)) |
| { |
| log->WriteAll(prep_stmt->outputBuf(),curpos,useCout); |
| firstRowDisplayed = TRUE; |
| } |
| |
| // Child QueryId Processing |
| if (doCTAS && (NOT noScreenOutput)) |
| { |
| if (strstr(prep_stmt->outputBuf(), "childQidBegin")) |
| { |
| Lng32 rc = SQL_EXEC_GetChildQueryInfo(stmt, |
| childQueryId, |
| ComSqlId::MAX_QUERY_ID_LEN, |
| &childQueryIdLen, |
| &childQueryCostInfo, |
| &childQueryCompilerStatsInfo); |
| HandleCLIError(rc, sqlci_env); |
| if (rc >= 0) |
| { |
| childQueryId[childQueryIdLen]='\0'; |
| sprintf(prep_stmt->outputBuf(), "Child Query Id about to execute is %s", childQueryId); |
| log->WriteAll(prep_stmt->outputBuf(), prep_stmt->outputBuflen(),useCout); |
| } |
| } |
| if (strstr(prep_stmt->outputBuf(), "childQidEnd")) |
| { |
| PrepStmt *saved_prep_stmt = prep_stmt; |
| sqlci_env->getStats()->displayChildQryStats(sqlci_env); |
| sqlci_env->lastExecutedStmt() = saved_prep_stmt; |
| } |
| } |
| |
| useCout = 0; |
| lastLineWasABlank = FALSE; |
| } |
| |
| // If this is a CALL statement that can return result sets, |
| // then the CALL has just executed and we now want to display |
| // all returned result sets |
| if (queryType == SQL_CALL_WITH_RESULT_SETS && |
| retcode >= 0 && !isResultSet) |
| { |
| processedCallWithResultSets = TRUE; |
| NABoolean done = FALSE; |
| Lng32 rsIndex = 1; |
| while (!done) |
| { |
| // long copyOfWorstcode = worstcode; |
| |
| DML *rs = new DML("", DML_CALL_STMT_RS_TYPE, |
| "__SQLCI_DML_SP_RESULT_SET__"); |
| rs->setResultSetIndex(rsIndex); |
| Lng32 rsProcessingCode = rs->process(sqlci_env); |
| |
| delete rs; |
| rsIndex++; |
| |
| // Not completely sure what to do with the worstcode |
| // variable now. If errors were encountered while |
| // displaying the last result set, worstcode will be |
| // SQL_Error. But if we are going to ignore that error and |
| // continue processing more result sets, maybe we should |
| // reset worstcode to the value of copyOfWorstcode. TBD... |
| //worstcode = copyOfWorstcode; |
| |
| // Restore last exec stmt pointer |
| sqlci_env->lastExecutedStmt() = prep_stmt; |
| |
| // Possible return values: 0, 1, SQL_Canceled |
| if (rsProcessingCode == 1 || |
| (rsProcessingCode < 0 && rsProcessingCode != SQL_Canceled)) |
| { |
| retcode = rsProcessingCode; |
| done = TRUE; |
| } |
| } // while (!done) |
| |
| } // End of CALL statement result set loop |
| |
| if (num_rows_returned == listcount && |
| stmt_type != DML_DESCRIBE_TYPE && |
| stmt_type != DML_SHOWSHAPE_TYPE) |
| listcountReached = TRUE; |
| else if (!processedCallWithResultSets) |
| { |
| if (NOT doCEFC) |
| retcode = doFetch(sqlci_env, stmt, prep_stmt); // get next row |
| else |
| retcode = SQL_Eof; |
| } |
| |
| } // while getting rows |
| |
| // close the statement, if an error was not received. The |
| // statement is already closed in case of an error. |
| if ((NOT doCEFC) && |
| (Succ_or_Warn || retcode == SQL_Eof || retcode == SQL_Canceled)) |
| { |
| retcode = SQL_EXEC_CloseStmt(stmt); |
| if (processedCallWithResultSets && |
| retcode == -8811) // statement already closed |
| { |
| SqlCmd::clearCLIDiagnostics(); |
| retcode = 0; |
| } |
| HandleCLIError(retcode, sqlci_env); |
| } |
| getRowsAffected(stmt); |
| |
| } // retcode >= 0 |
| |
| char donemsg[100]; |
| donemsg[0] = '\0'; |
| |
| switch (stmt_type) |
| { |
| case DML_UPDATE_TYPE: |
| case DML_DELETE_TYPE: |
| case DML_INSERT_TYPE: |
| case DML_UNLOAD_TYPE: |
| { |
| if (stmt_type == DML_UPDATE_TYPE) |
| sprintf(donemsg, UPDATED_MESSAGE, rowsAffected); |
| else if (stmt_type == DML_DELETE_TYPE) |
| sprintf(donemsg, DELETED_MESSAGE, rowsAffected); |
| else if (stmt_type == DML_INSERT_TYPE) |
| sprintf(donemsg, INSERTED_MESSAGE, rowsAffected); |
| else if (stmt_type == DML_UNLOAD_TYPE) |
| sprintf(donemsg, UNLOADED_MESSAGE, rowsAffected); |
| |
| } |
| break; |
| |
| case DML_CALL_STMT_RS_TYPE: |
| case DML_SELECT_TYPE: |
| { |
| if (! noScreenOutput) |
| sprintf(donemsg, SELECTED_MESSAGE, num_rows_returned); |
| else |
| { |
| if (displayFirstRow) |
| sprintf(donemsg, SELECTED_FIRST_ROW_DISPLAY_MESSAGE, num_rows_returned); |
| else |
| sprintf(donemsg, SELECTED_BUT_MESSAGE, num_rows_returned); |
| } |
| } |
| break; |
| |
| case DML_CONTROL_TYPE: |
| case DML_OSIM_TYPE: |
| case DML_DISPLAY_NO_HEADING_TYPE: |
| case DML_DESCRIBE_TYPE: |
| case DML_DDL_TYPE: |
| { |
| if (stmt_type == DML_DDL_TYPE && doHBL ) |
| sprintf(donemsg, LOADED_MESSAGE, rowsAffected); |
| else if (worstcode == SQL_Success || worstcode == SQL_Eof) |
| sprintf(donemsg, OP_COMPLETE_MESSAGE); |
| else if (worstcode < 0) |
| sprintf(donemsg, OP_COMPLETED_ERRORS); |
| else |
| sprintf(donemsg, OP_COMPLETED_WARNINGS); |
| } |
| break; |
| |
| case DML_DISPLAY_NO_ROWS_TYPE: |
| { |
| sprintf(donemsg, OP_COMPLETE_MESSAGE); |
| } |
| break; |
| |
| case DML_SHOWSHAPE_TYPE: |
| { |
| donemsg[0] = '\0'; // empty |
| } |
| break; |
| |
| default: |
| { |
| donemsg[0] = '\0'; // empty |
| } |
| break; |
| }// end of switch stmt |
| |
| if (listcountReached) |
| strcat(donemsg, LISTCOUNT_MESSAGE); |
| |
| if (!lastLineWasABlank) |
| { |
| log->WriteAll(""); |
| lastLineWasABlank = TRUE; |
| } |
| |
| if (donemsg[0] != '\0') |
| { |
| log->WriteAll(donemsg); |
| lastLineWasABlank = FALSE; |
| } |
| |
| if ((retcode < 0) && (retcode != SQL_Canceled)) |
| return SQL_Error; |
| else |
| return ((short)retcode); |
| } |
| |
| short SqlCmd::executeQuery(const char *query, SqlciEnv *sqlci_env) |
| { |
| // ----------------------------------------------------------------------- |
| // Given a SQL query, this procedure invokes the appropriate |
| // CLI calls to prepare and execute the statement. |
| // ----------------------------------------------------------------------- |
| Lng32 retcode; |
| |
| SQLMODULE_ID module; |
| init_SQLMODULE_ID(&module); |
| |
| SQLSTMT_ID *stmt = new SQLSTMT_ID; |
| SQLDESC_ID *sql_src = new SQLDESC_ID; |
| memset (stmt, 0, sizeof(SQLSTMT_ID)); |
| memset (sql_src, 0, sizeof(SQLDESC_ID)); |
| |
| // Allocate a SQL statement |
| init_SQLSTMT_ID(stmt, SQLCLI_CURRENT_VERSION, stmt_handle, &module); |
| |
| retcode = SQL_EXEC_AllocStmt(stmt, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| // Allocate a descriptor which will hold the SQL statement source |
| init_SQLDESC_ID(sql_src, SQLCLI_CURRENT_VERSION, desc_handle, &module); |
| |
| retcode = SQL_EXEC_AllocDesc(sql_src, 1); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_TYPE_FS, |
| REC_BYTE_V_ANSI, 0); |
| retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_LENGTH, |
| strlen(query) + 1, 0); |
| retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_CHAR_SET_NAM, |
| 0,(char*)CharInfo::getCharSetName(sqlci_env->getTerminalCharset())); |
| retcode = SQL_EXEC_SetDescItem(sql_src, 1, SQLDESC_VAR_PTR, |
| (Long)query, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| // execute immediate this statement |
| Int32 prep_flags = 0; |
| retcode = SQL_EXEC_ExecDirect2(stmt, sql_src,prep_flags, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| |
| // free up resources |
| retcode = SQL_EXEC_DeallocDesc(sql_src); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DeallocStmt(stmt); |
| HandleCLIError(retcode, sqlci_env); |
| |
| delete stmt; |
| delete sql_src; |
| |
| // return ((retcode < 0) ? SQL_Error : retcode); |
| // avoid compiler warning |
| return (short)((retcode < 0) ? SQL_Error : retcode); |
| |
| } |
| |
| short SqlCmd::setEnviron(SqlciEnv *sqlci_env, Lng32 propagate) |
| { |
| short rc = SQL_EXEC_SetEnviron_Internal(propagate); |
| return rc; |
| } |
| |
| |
| DML::DML(const char * argument_, dml_type type_, const char * stmt_name_) |
| : SqlCmd(SqlCmd::DML_TYPE, argument_), rsIndex_(0) |
| { |
| if (stmt_name_) |
| { |
| this_stmt_name = new char[strlen(stmt_name_) + 1]; |
| strcpy(this_stmt_name, stmt_name_); |
| } |
| else |
| this_stmt_name = NULL; |
| |
| type = type_; |
| } |
| |
| DML::~DML() |
| { |
| } |
| |
| Prepare::Prepare(char * stmt_name_, char * argument_, dml_type type_) |
| : SqlCmd(SqlCmd::PREPARE_TYPE, argument_) |
| { |
| this_stmt_name = new char[strlen(stmt_name_) + 1]; |
| strcpy(this_stmt_name, stmt_name_); |
| type = type_; |
| } |
| |
| Prepare::~Prepare() |
| { |
| delete [] this_stmt_name; |
| } |
| |
| DescribeStmt::DescribeStmt(char * stmtName, char * argument) : |
| SqlCmd(SqlCmd::DESCRIBE_TYPE, argument){ |
| stmtName_ = new char[strlen(stmtName) + 1]; |
| strcpy(stmtName_, stmtName); |
| } |
| |
| DescribeStmt::~DescribeStmt(){ |
| delete [] stmtName_; |
| } |
| |
| Cursor::Cursor(char * cursorName, CursorOperation operation, |
| short internalPrepare, char * argument, |
| NABoolean internalCursor) |
| : SqlCmd(SqlCmd::CURSOR_TYPE, argument), isHoldable_(FALSE), |
| resultSetIndex_(0), internalCursor_(internalCursor) |
| { |
| cursorName_ = new char[strlen(cursorName) + 1]; |
| strcpy(cursorName_, cursorName); |
| operation_ = operation; |
| internalPrepare_ = internalPrepare; |
| } |
| |
| Cursor::~Cursor() |
| { |
| delete [] cursorName_; |
| } |
| |
| Execute::Execute(char * stmt_name_, char * argument_, short flag, SqlciEnv * sqlci_env) |
| : SqlCmd(SqlCmd::EXECUTE_TYPE, argument_) |
| { |
| this_stmt_name = new char[strlen(stmt_name_) + 1]; |
| strcpy(this_stmt_name, stmt_name_); |
| num_params = 0; |
| |
| for ( Int32 i=0; i<MAX_NUM_UNNAMED_PARAMS; i++ ) |
| using_param_charsets[i]=CharInfo::UnknownCharSet; |
| |
| if (flag) |
| { |
| Lng32 err = storeParams(argument_, num_params, using_params, using_param_charsets, sqlci_env); |
| if (err) |
| setErrorCode(err); |
| } |
| } |
| |
| Execute::~Execute() |
| { |
| delete [] this_stmt_name; |
| for (Int32 i = num_params; i > 0; ) |
| delete [] using_params[--i]; |
| } |
| |
| /*******************************************************/ |
| /* store unnamed parameters in an array */ |
| /* example: execute <stmt name> using 24, cat, 'dog'; */ |
| /* input: 24, cat, 'dog'; */ |
| /* output: none */ |
| /*******************************************************/ |
| static Lng32 errorParams(Lng32 err, |
| const char *str0 = NULL, Lng32 int0 = -99) |
| { |
| sqlci_DA << DgSqlCode(err) << DgString0(str0) << DgInt0(int0); |
| return err; |
| } |
| |
| Lng32 Execute::storeParams(char* argument_, short &num_params, |
| char * using_params[], |
| CharInfo::CharSet using_param_charsets[], |
| SqlciEnv *sqlci_env) |
| { |
| ComASSERT(argument_); |
| num_params = 0; |
| |
| // Trim trailing blanks and semicolons |
| size_t arglen = strlen(argument_); |
| for (; arglen; arglen--) |
| if (!isspace((unsigned char)argument_[arglen-1]) && argument_[arglen-1] != ';') // For VS2003 |
| break; |
| |
| char sentinel = argument_[arglen]; // either ';' or '\0' |
| argument_[arglen] = '\0'; // now '\0' |
| |
| // Get past leading blanks |
| char *args = argument_; |
| while (*args) |
| { |
| NABoolean literal = TRUE; // if this arg is a literal, set it to 1 |
| // otherwise, set it to 0. It's set to 1 as default. |
| while (isspace((unsigned char)*args)) args++; // For VS2003 |
| |
| if (num_params >= MAX_NUM_UNNAMED_PARAMS) |
| return errorParams(-SQLCI_NUM_PARAMS_OVERFLOW, |
| NULL, |
| MAX_NUM_UNNAMED_PARAMS); |
| |
| char *errarg = args; // points to a non-blank value |
| char param[MAX_LEN_UNNAMED_PARAM+1]; // buffer for current value |
| size_t i = 0; // len(param)+1 |
| |
| if ( using_param_charsets && *args == '_' ) { |
| char* prefixPtr = args+1; |
| while ( *prefixPtr ) { |
| if ( *prefixPtr == '\'' ) { |
| |
| // check if a valid charset name is found |
| |
| // upper case the name first |
| Int32 nameLen = prefixPtr-args-1; |
| char* upperCaseName = new char[nameLen+1]; |
| |
| Int32 j; |
| for ( j =0; j<nameLen; j++) { |
| upperCaseName[j] = (char)TOUPPER(args[j+1]); |
| } |
| upperCaseName[j] = 0; |
| |
| // name lookup |
| CharInfo::CharSet cs = CharInfo::getCharSetEnum(upperCaseName); |
| delete [] upperCaseName; |
| |
| if (CharInfo::isCharSetFullySupported(cs)) { |
| errarg = args = prefixPtr; // advance the point to true start of the literal |
| } else { |
| *prefixPtr= '\0'; // terminate errarg at '\'' |
| return errorParams(-SQLCI_SYNTAX_ERROR, errarg); |
| } |
| |
| // fill the charset. If the prefix specifies an unsupported name, |
| // the cs is CharInfo::UnknownCharSet. |
| using_param_charsets[num_params] = cs; |
| |
| break; |
| } |
| prefixPtr++; |
| } |
| } |
| |
| switch (*args) |
| { |
| case '\'': // Convert 'ab' to ab, 'ab''c' to ab'c |
| // because basically we want |
| // USING 'ab' and USING ab |
| // to be equivalent. |
| { |
| char *qseen = errarg; // points to beginning ' of args |
| while (*args++ && |
| i < MAX_LEN_UNNAMED_PARAM) |
| { |
| if (*args == '\'') |
| if (args[1] != '\'') |
| { qseen = args++; break; } // ending ' of args |
| else |
| param[i++] = *args++; // yes, ++ to skip one ' of '' |
| else |
| param[i++] = *args; // no ++ (while does it) |
| } |
| |
| if ( CharInfo::UnknownCharSet == using_param_charsets[num_params] ) |
| { |
| // The character set attribute of a quoted string without a charset prefix is ... |
| if (sqlci_env != NULL) |
| using_param_charsets[num_params] = sqlci_env->getTerminalCharset(); |
| else |
| using_param_charsets[num_params] = CharInfo::UnknownCharSet; |
| } |
| else { |
| // MP KANJI/KSC5601's params should be even in length |
| if ( CharInfo::is_NCHAR_MP(using_param_charsets[num_params]) && |
| i % 2 != 0 |
| ) { |
| *args = '\0'; // terminate errarg |
| return errorParams(-SQLCI_SYNTAX_ERROR, errarg); |
| } |
| } |
| |
| |
| if (i >= MAX_LEN_UNNAMED_PARAM) |
| { |
| *args = '\0'; // terminate errarg |
| return errorParams(-SQLCI_LEN_PARAM_OVERFLOW, |
| errarg, |
| MAX_LEN_UNNAMED_PARAM); |
| } |
| if (qseen == errarg) |
| return errorParams(-SQLCI_INPUT_MISSING_QUOTE, |
| errarg); |
| while (isspace((unsigned char)*args)) args++; // go past trailing blanks// For VS2003 |
| if (*args && *args != ',') |
| { |
| *++qseen = '\0'; // terminate errarg after end ' |
| return errorParams(-SQLCI_PARAM_QUOTED_BAD_CONCAT, |
| errarg); |
| } |
| } |
| break; |
| |
| default: // Copy as is, including embedded squotes and blanks |
| // (leading blanks were already removed above), |
| // to param value buffer, until we hit a comma |
| // (the param value separator). |
| // Then remove trailing blanks. |
| // |
| // ## This is kinda weird, nonAnsi syntax, **AND** |
| // ## does not at all match the way sqlci_yacc rejects any of |
| // ## SET PARAM ?p val ue string; |
| // ## SET PARAM ?p val'ue'str''ing; |
| // ## Could definitely be fixed here for consistency -- |
| // ## i.e. reject embedded punctuation, esp ' and blanks... |
| // ## |
| // ## We do of course accept |
| // ## USING 'val ue string', 'val''ue''str''''ing'; |
| // ## the same way sqlci_yacc accepts |
| // ## SET PARAM ?p 'val ue string'; |
| // ## SET PARAM ?p 'val''ue''str''''ing'; |
| // ## so that part's good. |
| { |
| for ( ; |
| *args && *args != ',' && i < MAX_LEN_UNNAMED_PARAM; |
| args++) |
| param[i++] = isspace((unsigned char)*args) ? ' ' : *args; // For VS2003 |
| while (isspace((unsigned char)*args)) args++; // go past trailing blanks // For VS2003 |
| if (i >= MAX_LEN_UNNAMED_PARAM) |
| { |
| if (*args && *args != ',') |
| { |
| *args = '\0'; // terminate errarg |
| if (&errarg[MAX_LEN_UNNAMED_PARAM+60] < args) |
| errarg[MAX_LEN_UNNAMED_PARAM+60] = '\0'; |
| return errorParams(-SQLCI_LEN_PARAM_OVERFLOW, |
| errarg, |
| MAX_LEN_UNNAMED_PARAM); |
| } |
| } |
| while (i && isspace((unsigned char)param[i-1])) // Here, remove trailing// For VS2003 |
| i--; // blanks from param[]. |
| literal = FALSE; |
| |
| // ## Yuck, we also allow |
| // ## USING,,; equiv to USING '','',''; |
| // if (!i) return errorParams(-SQLCI_LEN_PARAM_UNDERFLOW); |
| } |
| } // switch *args |
| |
| if (*args) |
| { |
| ComASSERT(*args == ','); // all blanks are past; |
| args++; // go past the comma |
| // Convert a final comma (with a blank value "after" it) to a blank, |
| // to make a final unquoted blank value for our next (and last) while-iter |
| if (!*args) |
| *--args = ' '; |
| } |
| |
| // dynamically get space for the param value and store it in the array |
| param[i] = '\0'; |
| |
| //if there's a NULL value and it was not included in quotes, the param |
| //value is NULL. Otherwise, allocate a space for the param value in |
| //using_params |
| if (!literal && !strcmp(param, "NULL")) |
| using_params[num_params] = NULL; |
| else { |
| using_params[num_params] = new char[i+1]; |
| strcpy(using_params[num_params], param); |
| } |
| num_params++; |
| } // while *args |
| |
| argument_[arglen] = sentinel; // reset back to ';' or '\0' |
| |
| if (!num_params) |
| return errorParams(-SQLCI_NUM_PARAMS_UNDERFLOW); |
| |
| return 0; // no error |
| } |
| |
| QueryCacheSt::QueryCacheSt(short option) |
| : SqlCmd(SqlCmd::QUERYCACHE_TYPE, ""), |
| option_(option) |
| {} |
| |
| short SqlCmd::deallocate(SqlciEnv * sqlci_env, PrepStmt * prep_stmt) |
| { |
| Lng32 retcode; |
| |
| // prepared statement exists. Deallocate it. |
| retcode = SQL_EXEC_DeallocDesc(prep_stmt->getSqlSrc()); |
| if (prep_stmt->getSqlSrc()) |
| { |
| if (prep_stmt->getSqlSrc()->module) |
| delete (SQLMODULE_ID *)prep_stmt->getSqlSrc()->module; |
| prep_stmt->getSqlSrc()->module = NULL; |
| } |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DeallocDesc(prep_stmt->getInputDesc()); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DeallocDesc(prep_stmt->getOutputDesc()); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DeallocStmt(prep_stmt->getStmt()); |
| if (prep_stmt->getStmt()) |
| { |
| if (prep_stmt->getStmt()->module) |
| delete (SQLMODULE_ID *)prep_stmt->getStmt()->module; |
| if (prep_stmt->getStmt()->identifier) |
| delete [] (char *)prep_stmt->getStmt()->identifier; |
| prep_stmt->getStmt()->identifier = NULL; |
| } |
| |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (prep_stmt) |
| delete prep_stmt; |
| prep_stmt = NULL; |
| |
| return retcode; |
| } |
| |
| |
| |
| ///////////////////////////////////////////////////////////////// |
| // ::process() methods |
| ///////////////////////////////////////////////////////////////// |
| |
| short DML::process(SqlciEnv * sqlci_env) |
| { |
| Lng32 retcode = 0, prepcode = 0, retcodeExe = 0; |
| |
| // Bookkeeping for stored procedure result sets |
| NABoolean isResultSet = (type == DML_CALL_STMT_RS_TYPE ? TRUE : FALSE); |
| NABoolean skipStats = isResultSet; |
| |
| if (!isResultSet) |
| HandleCLIErrorInit(); |
| |
| char dml_stmt_name[50]; |
| // if this_stmt_name is not NULL, then this method was invoked by |
| // an sqlci internal method (like stats...etc). |
| if (! this_stmt_name) |
| strcpy(dml_stmt_name, "__SQLCI_DML_LAST__"); // generate a dummy name |
| else |
| strcpy(dml_stmt_name, this_stmt_name); |
| |
| PrepStmt * prep_stmt; |
| if (prep_stmt = sqlci_env->get_prep_stmts()->get(dml_stmt_name)) |
| { |
| // this statement name should not be present in the list of prepared |
| // stmts as it is an internal name. If we reach this error, it |
| // means that someone has prepared a statement with the same |
| // name as what we used internally. We need to fix our internal |
| // name. |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_INTERNAL_ERROR); |
| return 0; |
| } |
| |
| prep_stmt = new PrepStmt(dml_stmt_name, type); |
| |
| if (!skipStats) |
| sqlci_env->getStats()->startStats(prep_stmt); |
| |
| NABoolean resetLastExecStmt = (isResultSet ? FALSE : TRUE); |
| Int32 prepareCode = 0; |
| Lng32 statisticsType = SQLCLI_NO_STATS; |
| prepcode = do_prepare(sqlci_env, prep_stmt, get_sql_stmt(), |
| resetLastExecStmt, rsIndex_,&prepareCode, &statisticsType); |
| if (statisticsType == SQLCLI_NO_STATS) |
| skipStats = TRUE; |
| if (!skipStats) |
| sqlci_env->getStats()->startExeStats(); |
| |
| if (prepcode >= 0) |
| { |
| NABoolean skipExec = FALSE; |
| char * po = sqlci_env->getPrepareOnly(); |
| char * eo = sqlci_env->getExecuteOnly(); |
| if (!po && !eo) |
| { |
| retcodeExe = do_execute(sqlci_env, prep_stmt, 0, NULL, NULL, prepareCode); |
| } |
| else |
| { |
| // only adding prepareOnly for DML. Other cases could |
| // be added later. |
| if ((po) && (strcmp(po, "DML") == 0) && |
| ((prep_stmt->getType() == DML_SELECT_TYPE) || |
| (prep_stmt->getType() == DML_UPDATE_TYPE) || |
| (prep_stmt->getType() == DML_INSERT_TYPE) || |
| (prep_stmt->getType() == DML_DELETE_TYPE))) |
| { |
| // don't execute in this case. |
| sqlci_env->lastExecutedStmt() = NULL; |
| |
| Logfile *log = sqlci_env->get_logfile(); |
| if (!lastLineWasABlank) log->WriteAll(""); |
| log->WriteAll(PREPARED_MESSAGE); |
| } |
| else |
| { |
| retcodeExe = do_execute(sqlci_env, prep_stmt); |
| } |
| } |
| } |
| |
| if (!skipStats) |
| { |
| sqlci_env->getStats()->endExeStats(); |
| sqlci_env->getStats()->endStats(sqlci_env); |
| } |
| |
| // if stats were collected for this statement, then do not |
| // deallocate it. Deallocating the stmt will destroy the stats area |
| // in executor and a subsequent 'display statistics' command will |
| // not be able to display stats. |
| // This statement will be deallocated when the next standalone |
| // statement is issued from sqlci. |
| |
| NABoolean deallocStmt = ((prepcode >= 0) ? TRUE : FALSE); |
| |
| // do not display stats for internal invocations. Do it for user |
| // entered standalone non-prepared queries only. |
| if ((this_stmt_name == NULL) && (deallocStmt) && |
| (sqlci_env->lastExecutedStmt()) && |
| (statisticsType != SQLCLI_NO_STATS)) |
| { |
| sqlci_env->getStats()->displayStats(sqlci_env); |
| } |
| |
| if (deallocStmt) |
| { |
| retcode = deallocate(sqlci_env, prep_stmt); |
| // if the stmt has already been deallocated then |
| // there is no need to deallocate it in the interrupt handler. |
| if (!isResultSet) |
| { |
| if (! retcode) |
| global_sqlci_env->resetDeallocateStmt() ; |
| sqlci_env->lastExecutedStmt() = NULL; |
| } |
| } |
| |
| if ( breakReceived ) |
| { |
| breakReceived = 0; |
| |
| if ((prepcode >= 0) && (retcodeExe != SQL_Canceled) && (retcodeExe != SQL_Rejected)) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(SQLCI_BREAK_RECEIVED, DgSqlCode::WARNING_); |
| return SQL_Canceled; |
| } |
| } |
| |
| // TEMP TEMP |
| // Sometimes inserted rows are not being flushed out. That causes selected |
| // rows to not get returned. |
| // Temporarily add a one sec delay so it can get flushed out. |
| // Do this only for regressions run. |
| if ((prep_stmt) && (prep_stmt->getType() == DML_INSERT_TYPE) && |
| (getenv("SQLMX_REGRESS"))) |
| { |
| //DELAY(100); |
| } |
| |
| if ((prepcode >= 0) && (retcodeExe == SQL_Canceled)) |
| { |
| return (short)retcodeExe; |
| } |
| else |
| { |
| if (prepcode) |
| return 1; |
| else |
| return 0; |
| } |
| } // end DML::process |
| |
| |
| ///////////////////////////////////////////// |
| // Begin PREPARE |
| ////////////////////////////////////////////// |
| short Prepare::process(SqlciEnv * sqlci_env) |
| { |
| Lng32 retcode; |
| HandleCLIErrorInit(); |
| PrepStmt * prep_stmt; |
| |
| if (prep_stmt = sqlci_env->get_prep_stmts()->get(this_stmt_name)) |
| { |
| // prepared statement exists. Deallocate it. |
| retcode = SQL_EXEC_DeallocDesc(prep_stmt->getSqlSrc()); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DeallocDesc(prep_stmt->getInputDesc()); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DeallocDesc(prep_stmt->getOutputDesc()); |
| HandleCLIError(retcode, sqlci_env); |
| |
| retcode = SQL_EXEC_DeallocStmt(prep_stmt->getStmt()); |
| HandleCLIError(retcode, sqlci_env); |
| |
| sqlci_env->get_prep_stmts()->remove(this_stmt_name); |
| } |
| |
| prep_stmt = new PrepStmt(this_stmt_name, type); |
| |
| sqlci_env->getStats()->startStats(prep_stmt); |
| retcode = do_prepare(sqlci_env, prep_stmt, get_sql_stmt()); |
| sqlci_env->getStats()->endStats(sqlci_env); |
| |
| // if do_prepare was successfull then reset |
| // the deallocate stmt in global_sqlci_env |
| // in case of a break. |
| if (retcode >= 0) |
| { |
| global_sqlci_env->resetDeallocateStmt() ; |
| } |
| |
| |
| if (retcode >= 0) |
| { |
| sqlci_env->get_prep_stmts()->append(prep_stmt); |
| |
| Logfile *log = sqlci_env->get_logfile(); |
| if (!lastLineWasABlank) log->WriteAll(""); |
| log->WriteAll(PREPARED_MESSAGE); |
| } |
| |
| // This is Prepare; no Exe time at all |
| sqlci_env->getStats()->startExeStats(); |
| sqlci_env->getStats()->endExeStats(); |
| |
| sqlci_env->getStats()->displayStats(sqlci_env); |
| |
| return 0; |
| } |
| |
| // Prepare::process has already set up the PrepStmt by calling |
| // DescribeStmt CLI call and allocate PrepStmt. Some descriptor items |
| // has already been extracted from the output descriptor, such as |
| // type, length, precision, scale. |
| /////////////////////////////////////////////////////// |
| // Begin DESCRIBESTMT |
| ////////////////////////////////////////////////////// |
| short DescribeStmt::displayEntries(SqlciEnv *sqlci_env, |
| SQLDESC_ID *desc, Lng32 numEntries, |
| Logfile *log) |
| { |
| char scratchBuffer[512]; |
| char charVal[ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN+1]; |
| Lng32 intVal; |
| Lng32 retcode; |
| |
| // For each entry produce the following output |
| // |
| // [i] NAME "column-name", HEADING "column-heading" |
| // TYPE n, FS n, LEN n, OCTLEN n, CHARSET n |
| // PREC n, LPREC n, SCALE n, DTCODE n, NULL n, MODE n, IDX n, ORDPOS n |
| // CAT "catalog-name", SCH "schema-name", TABLE "table-name" |
| |
| for (Lng32 entry = 1; entry <= numEntries; entry++) |
| { |
| sprintf(scratchBuffer, "[%d] ", entry); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_NAME, |
| 0, charVal, |
| ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN, |
| &intVal, 0); |
| HandleCLIError(retcode, sqlci_env); |
| charVal[intVal] = 0; |
| sprintf(scratchBuffer, "NAME \"%s\", ", charVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_HEADING, |
| 0, charVal, |
| ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN, |
| &intVal, 0); |
| HandleCLIError(retcode, sqlci_env); |
| charVal[intVal] = 0; |
| sprintf(scratchBuffer, "HEADING \"%s\"", charVal); |
| log->WriteAll(scratchBuffer); |
| |
| // ------------------------------------------------ |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_TYPE, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, " TYPE %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_TYPE_FS, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "FS %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_LENGTH, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "LEN %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_OCTET_LENGTH, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "OCTLEN %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_CHAR_SET, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "CHARSET %d", intVal); |
| log->WriteAll(scratchBuffer); |
| |
| // ------------------------------------------------ |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_PRECISION, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, " PREC %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_INT_LEAD_PREC, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "LPREC %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_SCALE, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "SCALE %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_DATETIME_CODE, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "DTCODE %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_NULLABLE, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "NULL %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_PARAMETER_MODE, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "MODE %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_PARAMETER_INDEX, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "IDX %d, ", intVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_ORDINAL_POSITION, |
| &intVal, 0, 0, 0, 0); |
| HandleCLIError(retcode, sqlci_env); |
| sprintf(scratchBuffer, "ORDPOS %d", intVal); |
| log->WriteAll(scratchBuffer); |
| |
| // ------------------------------------------------ |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_CATALOG_NAME, |
| 0, charVal, |
| ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN, |
| &intVal, 0); |
| HandleCLIError(retcode, sqlci_env); |
| charVal[intVal] = 0; |
| sprintf(scratchBuffer, " CAT \"%s\", ", charVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_SCHEMA_NAME, |
| 0, charVal, |
| ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN, |
| &intVal, 0); |
| HandleCLIError(retcode, sqlci_env); |
| charVal[intVal] = 0; |
| sprintf(scratchBuffer, "SCH \"%s\", ", charVal); |
| log->WriteAllWithoutEOL(scratchBuffer); |
| |
| retcode = SQL_EXEC_GetDescItem(desc, entry, |
| SQLDESC_TABLE_NAME, |
| 0, charVal, |
| ComAnsiNamePart::MAX_IDENTIFIER_EXT_LEN, |
| &intVal, 0); |
| HandleCLIError(retcode, sqlci_env); |
| charVal[intVal] = 0; |
| sprintf(scratchBuffer, "TABLE \"%s\"", charVal); |
| log->WriteAll(scratchBuffer); |
| |
| } |
| |
| return 0; |
| } |
| |
| short DescribeStmt::process(SqlciEnv * sqlci_env) |
| { |
| HandleCLIErrorInit(); |
| PrepStmt *prep_stmt; |
| |
| if (!(prep_stmt = sqlci_env->get_prep_stmts()->get(stmtName_))) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(stmtName_); |
| return 0; |
| } |
| |
| sqlci_env->getStats()->startStats(prep_stmt); |
| sqlci_env->getStats()->startExeStats(); |
| |
| // meat of the body |
| Logfile *log = sqlci_env->get_logfile(); |
| SQLDESC_ID * input_desc = prep_stmt->getInputDesc(); |
| SQLDESC_ID * output_desc = prep_stmt->getOutputDesc(); |
| Lng32 num_input_entries = prep_stmt->numInputEntries(); |
| Lng32 num_output_entries = prep_stmt->numOutputEntries(); |
| |
| if (num_input_entries > 0) |
| { |
| log->WriteAll("---Describing the INPUT entries---"); |
| displayEntries(sqlci_env, input_desc, num_input_entries, log); |
| } |
| |
| if (num_output_entries > 0) |
| { |
| log->WriteAll("---Describing the OUTPUT entries---"); |
| displayEntries(sqlci_env, output_desc, num_output_entries, log); |
| } |
| |
| // eye marker |
| sqlci_env->getStats()->endExeStats(); |
| sqlci_env->getStats()->endStats(sqlci_env); |
| |
| sqlci_env->getStats()->displayStats(sqlci_env); |
| |
| return 0; |
| } |
| |
| short StoreExplain::process(SqlciEnv * sqlci_env) |
| { |
| Lng32 retcode; |
| HandleCLIErrorInit(); |
| PrepStmt * prep_stmt; |
| |
| if (!(prep_stmt = sqlci_env->get_prep_stmts()->get(get_sql_stmt()))) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(get_sql_stmt()); |
| return 0; |
| } |
| |
| retcode = updateRepos(sqlci_env, prep_stmt->getStmt(), prep_stmt->uniqueQueryId()); |
| |
| char donemsg[100]; |
| donemsg[0] = '\0'; |
| |
| if (retcode == 0) |
| sprintf(donemsg, OP_COMPLETE_MESSAGE); |
| else if (retcode > 0) |
| sprintf(donemsg, OP_COMPLETED_WARNINGS); |
| else |
| sprintf(donemsg, OP_COMPLETED_ERRORS); |
| |
| Logfile *log = sqlci_env->get_logfile(); |
| if (!lastLineWasABlank) |
| { |
| log->WriteAll(""); |
| lastLineWasABlank = TRUE; |
| } |
| |
| if (donemsg[0] != '\0') |
| { |
| log->WriteAll(donemsg); |
| lastLineWasABlank = FALSE; |
| } |
| |
| return 0; |
| } |
| |
| /////////////////////////////////////////// |
| /// Begin Execute |
| /////////////////////////////////////////// |
| |
| short Execute::process(SqlciEnv * sqlci_env) |
| { |
| Lng32 retcode; |
| HandleCLIErrorInit(); |
| PrepStmt * prep_stmt; |
| |
| if (!(prep_stmt = sqlci_env->get_prep_stmts()->get(this_stmt_name))) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(this_stmt_name); |
| return 0; |
| } |
| |
| sqlci_env->getStats()->startStats(prep_stmt); |
| sqlci_env->getStats()->startExeStats(); |
| |
| retcode = do_execute(sqlci_env, prep_stmt, |
| getNumParams(), |
| getUnnamedParamArray(), |
| getUnnamedParamCharSetArray()); |
| |
| sqlci_env->getStats()->endExeStats(); |
| sqlci_env->getStats()->endStats(sqlci_env); |
| |
| sqlci_env->getStats()->displayStats(sqlci_env); |
| |
| return 0; |
| } |
| |
| ////////////////////////////////////////// |
| // Begin Cursor |
| ////////////////////////////////////////// |
| |
| // return of -1 is error, cursor operation was not done. |
| // return of 0 is returned with some cursor/cli operation done. |
| // retcode contains indication if it succeeded(=0) or failed(!= 0) |
| short Cursor::declareC(SqlciEnv * sqlci_env, char * donemsg, |
| Lng32 &retcode) |
| { |
| short result = 0; |
| |
| HandleCLIErrorInit(); |
| |
| if (resultSetIndex_ > 0) |
| result = declareCursorStmtForRS(sqlci_env, retcode); |
| else |
| result = declareCursorStmt(sqlci_env, retcode); |
| |
| if (donemsg) |
| { |
| if (retcode >= 0) |
| sprintf(donemsg, OP_COMPLETE_MESSAGE); |
| else |
| sprintf(donemsg, OP_COMPLETED_ERRORS); |
| } |
| |
| // This is Declare; no Exe time at all |
| sqlci_env->getStats()->startExeStats(); |
| sqlci_env->getStats()->endExeStats(); |
| sqlci_env->getStats()->displayStats(sqlci_env); |
| |
| return result; |
| } |
| |
| // return of -1 is error, cursor operation was not done. |
| // return of 0 is returned with some cursor/cli operation done. |
| // retcode contains indication if it succeeded(=0) or failed(!= 0) |
| short Cursor::declareCursorStmt(SqlciEnv *sqlci_env, Lng32 &retcode) |
| { |
| short result = 0; |
| CursorStmt * cursor; |
| PrepStmt * prepStmt = NULL; |
| |
| retcode = SQL_Success; |
| if (! internalPrepare_) |
| { |
| // make sure that the prepared stmt exists. |
| if (! (prepStmt = sqlci_env->get_prep_stmts()->get(get_sql_stmt()))) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(get_sql_stmt()); |
| return -1; |
| } |
| } |
| |
| if (cursor = sqlci_env->getCursorList()->get(cursorName_)) |
| { |
| cleanupCursorStmt(sqlci_env, cursor); |
| cursor = NULL; |
| } |
| |
| if (internalPrepare_) |
| { |
| NAString nameForPrepStmt("__SQLCI_PREPSTMT_FOR_CURSOR_"); |
| nameForPrepStmt += cursorName_; |
| nameForPrepStmt += "__"; |
| prepStmt = new PrepStmt(nameForPrepStmt.data()); |
| |
| sqlci_env->getStats()->startStats(prepStmt); |
| |
| // sqlci makes all SELECT's to be readonly by issuing a |
| // control command at startup time. Since this is an explicit |
| // DECLARE cursor statement which could later be updated/deleted |
| // using an "upd/del...where current of" statement, temporarily |
| // turn the readonly_cursor off. Turn it back on after this |
| // query has been prepared. |
| // If this is not an internal prepare, then users will have to |
| // specify the FOR UPDATE OF clause when they prepare the SELECT. |
| // Otherwise they will not be able to do a cursor update/delete. |
| retcode = |
| executeQuery("CONTROL QUERY DEFAULT READONLY_CURSOR 'FALSE';", |
| sqlci_env); |
| |
| if (retcode >= 0) // QSTUFF |
| { |
| Lng32 prepcode = do_prepare(sqlci_env, prepStmt, get_sql_stmt()); |
| |
| retcode = |
| executeQuery("CONTROL QUERY DEFAULT READONLY_CURSOR 'TRUE';", |
| sqlci_env); |
| |
| if (retcode >= 0 && prepcode) |
| retcode = prepcode; |
| } |
| |
| sqlci_env->getStats()->endStats(sqlci_env); |
| } |
| else |
| retcode = 0; |
| |
| ComASSERT(prepStmt); |
| |
| if (retcode >= 0) |
| { |
| // Make a copy of the cursor name |
| UInt32 nameLen = strlen(cursorName_); |
| char *identifier = new char[nameLen + 1]; |
| strcpy(identifier, cursorName_); |
| |
| // Make a statement ID for the new cursor |
| SQLSTMT_ID *cursorStmtId = new SQLSTMT_ID; |
| memset(cursorStmtId, 0, sizeof(SQLSTMT_ID)); |
| cursorStmtId->version = SQLCLI_CURRENT_VERSION; |
| cursorStmtId->name_mode = cursor_name; |
| cursorStmtId->identifier_len = (Lng32) nameLen; |
| cursorStmtId->identifier = identifier; |
| cursorStmtId->handle = 0; |
| cursorStmtId->module = prepStmt->getStmt()->module; |
| |
| retcode = SQL_EXEC_AllocStmt(cursorStmtId, prepStmt->getStmt()); |
| HandleCLIError(retcode, sqlci_env); |
| |
| // QSTUFF: set the holdable cursor flag if necessary |
| if (isHoldable()) |
| { |
| Lng32 attrValue = SQL_HOLDABLE; |
| |
| retcode = SQL_EXEC_SetStmtAttr(cursorStmtId, |
| SQL_ATTR_CURSOR_HOLDABLE, |
| attrValue, NULL); |
| HandleCLIError(retcode, sqlci_env); |
| if (retcode < 0) |
| { |
| Lng32 cleanupRetcode; |
| cleanupRetcode = SQL_EXEC_DeallocDesc(prepStmt->getSqlSrc()); |
| HandleCLIError(cleanupRetcode, sqlci_env); |
| |
| cleanupRetcode = SQL_EXEC_DeallocDesc(prepStmt->getInputDesc()); |
| HandleCLIError(cleanupRetcode, sqlci_env); |
| |
| cleanupRetcode = SQL_EXEC_DeallocDesc(prepStmt->getOutputDesc()); |
| HandleCLIError(cleanupRetcode, sqlci_env); |
| |
| cleanupRetcode = SQL_EXEC_DeallocStmt(prepStmt->getStmt()); |
| HandleCLIError(cleanupRetcode, sqlci_env); |
| } |
| } // if (isHoldable()) |
| |
| if (retcode >= 0) |
| { |
| cursor = new CursorStmt(cursorName_, cursorStmtId, |
| prepStmt, internalPrepare_); |
| |
| sqlci_env->getCursorList()->append(cursor); |
| } |
| else |
| { |
| delete [] identifier; |
| delete cursorStmtId; |
| } |
| } |
| |
| return result; |
| } // Cursor::declareCursorStmt |
| |
| // Create a CursorStmt object for a stored procedure result set |
| // return of -1 is error, cursor operation was not done. |
| // return of 0 is returned with some cursor/cli operation done. |
| // retcode contains indication if it succeeded(=0) or failed(!= 0) |
| short Cursor::declareCursorStmtForRS(SqlciEnv * sqlci_env, Lng32 &retcode) |
| { |
| short result = 0; // the return value of this function |
| PrepStmt *prepStmt = NULL; |
| CursorStmt *cursor = NULL; |
| CursorStmt *parentCursor = NULL; |
| char *nameOfParent = get_sql_stmt(); |
| |
| retcode = SQL_Success; |
| |
| // This is a stored procedure result set cursor. The |
| // parent must be another cursor, not a prepared |
| // statement. |
| parentCursor = sqlci_env->getCursorList()->get(nameOfParent); |
| if (!parentCursor) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(nameOfParent); |
| return -1; |
| } |
| |
| if (cursor = sqlci_env->getCursorList()->get(cursorName_)) |
| { |
| cleanupCursorStmt(sqlci_env, cursor); |
| cursor = NULL; |
| } |
| |
| // Create a PrepStmt for this result set. It will be used later to |
| // store the column descriptions. It doesn't get used for anything |
| // else. |
| NAString nameForPrepStmt("__SQLCI_PREPSTMT_FOR_CURSOR_"); |
| nameForPrepStmt += cursorName_; |
| nameForPrepStmt += "__"; |
| prepStmt = new PrepStmt(nameForPrepStmt.data()); |
| |
| // Give this PrepStmt instance a dummy name, so that SHOW CURSOR |
| // has something to display |
| char buf[100]; |
| sprintf(buf, "Result set %d, child of ", (Lng32) resultSetIndex_); |
| NAString dummyName(buf); |
| dummyName += nameOfParent; |
| |
| // Push values into the PrepStmt instance. Information about the |
| // output columns will be filled in later. It becomes available only |
| // after the parent CALL statement executes. |
| prepStmt->set((char *) dummyName.data(), |
| NULL, // SQLDESC_ID *sql_src_ |
| NULL, // SQLSTMT_ID *stmt_ |
| 0, // Lng32 numInputEntries |
| NULL, // SQLDESC_ID *input_desc_ |
| 0, // Lng32 numOutputEntries |
| NULL); // SQLDESC_ID *output_desc_ |
| |
| // Make a statement ID for the new result set statement |
| SQLSTMT_ID *childStmtId = new SQLSTMT_ID; |
| SQLSTMT_ID *parentStmtId = parentCursor->cursorStmtId(); |
| *childStmtId = *parentStmtId; |
| childStmtId->name_mode = stmt_handle; |
| childStmtId->identifier = NULL; |
| childStmtId->identifier_len = 0; |
| |
| retcode = SQL_EXEC_AllocStmtForRS(parentStmtId, |
| resultSetIndex_, |
| childStmtId); |
| HandleCLIError(retcode, sqlci_env); |
| |
| if (retcode >= 0) |
| { |
| cursor = new CursorStmt(cursorName_, childStmtId, |
| prepStmt, FALSE); |
| cursor->setResultSetIndex(resultSetIndex_); |
| sqlci_env->getCursorList()->append(cursor); |
| } |
| else |
| delete prepStmt; |
| |
| return result; |
| } // Cursor::decalreCursorStmtForRS |
| |
| // return of -1 is error, cursor operation was not done. |
| // return of 0 is returned with some cursor/cli operation done. |
| // retcode contains indication if it succeeded(=0) or failed(!= 0) |
| short Cursor::open(SqlciEnv * sqlci_env, char * donemsg, |
| Lng32 &retcode) |
| { |
| CursorStmt * cursor; |
| |
| HandleCLIErrorInit(); |
| |
| retcode = SQL_Success; |
| if (! (cursor = sqlci_env->getCursorList()->get(cursorName_))) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(cursorName_); |
| return -1; |
| } |
| |
| retcode = doExec(sqlci_env, |
| cursor->cursorStmtId(), |
| cursor->prepStmt()); |
| |
| if (retcode >= 0) |
| { |
| // If this is a stored procedure result set cursor then we now |
| // need to DESCRIBE the statement. The DESCRIBE can only be done |
| // reliably after the CALL statement executes, not necessarily at |
| // the time the cursor is DECLAREd. |
| if (cursor->getResultSetIndex() > 0) |
| { |
| PrepStmt *p = cursor->prepStmt(); |
| Lng32 num_output_entries = 0; |
| SQLDESC_ID *output_desc = p->getOutputDesc(); |
| |
| if (!output_desc) |
| { |
| output_desc = new SQLDESC_ID; |
| memset(output_desc, 0, sizeof(SQLDESC_ID)); |
| init_SQLDESC_ID(output_desc, |
| SQLCLI_CURRENT_VERSION, |
| desc_handle, |
| cursor->cursorStmtId()->module); |
| |
| retcode = SQL_EXEC_AllocDesc(output_desc, 500); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| if (retcode >= 0) |
| { |
| retcode = SQL_EXEC_DescribeStmt(cursor->cursorStmtId(), |
| NULL, |
| output_desc); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| if (retcode >= 0) |
| { |
| retcode = SQL_EXEC_GetDescEntryCount(output_desc, |
| &num_output_entries); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| if (retcode >= 0) |
| { |
| p->setOutputDesc(num_output_entries, output_desc); |
| addOutputInfoToPrepStmt(sqlci_env, p); |
| } |
| else |
| delete output_desc; |
| |
| } // if (cursor->getResultSetIndex() > 0) |
| } // if (retcode >= 0) |
| |
| if (retcode >= 0) |
| { |
| if (donemsg) |
| sprintf(donemsg, OP_COMPLETE_MESSAGE); |
| } |
| else |
| { |
| if (donemsg) |
| sprintf(donemsg, OP_COMPLETED_ERRORS); |
| } |
| |
| return 0; |
| } |
| |
| // return of -1 is error, cursor operation was not done. |
| // return of 0 is returned with some cursor/cli operation done. |
| // retcode contains indication if it succeeded(=0) or failed(!= 0) |
| short Cursor::fetch(SqlciEnv * sqlci_env, |
| NABoolean doDisplayRow, |
| char * donemsg, |
| Lng32 &retcode) |
| { |
| CursorStmt * cursor; |
| |
| HandleCLIErrorInit(); |
| |
| retcode = SQL_Success; |
| if (! (cursor = sqlci_env->getCursorList()->get(cursorName_))) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(cursorName_); |
| return -1; |
| } |
| |
| PrepStmt *p = cursor->prepStmt(); |
| if (p && p->numOutputEntries() < 1) |
| doDisplayRow = FALSE; |
| |
| retcode = doFetch(sqlci_env, |
| cursor->cursorStmtId(), |
| p); |
| if (Succ_or_Warn) |
| { |
| if (doDisplayRow) |
| { |
| displayHeading(sqlci_env, p); |
| |
| displayRow(sqlci_env, p); |
| |
| Logfile *log = sqlci_env->get_logfile(); |
| log->WriteAll(p->outputBuf()); |
| lastLineWasABlank = FALSE; |
| } |
| |
| if (donemsg) |
| sprintf(donemsg, SELECTED_MESSAGE, 1); |
| } |
| else |
| { |
| if (donemsg) |
| sprintf(donemsg, SELECTED_MESSAGE, 0); |
| } |
| |
| return 0; |
| } |
| |
| // return of -1 is error, cursor operation was not done. |
| // return of 0 is returned with some cursor/cli operation done. |
| // retcode contains indication if it succeeded(=0) or failed(!= 0) |
| short Cursor::close(SqlciEnv * sqlci_env, char * donemsg, |
| Lng32 &retcode) |
| { |
| CursorStmt * cursor; |
| |
| HandleCLIErrorInit(); |
| |
| retcode = SQL_Success; |
| if (! (cursor = sqlci_env->getCursorList()->get(cursorName_))) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(cursorName_); |
| return -1; |
| } |
| |
| retcode = SQL_EXEC_CloseStmt(cursor->cursorStmtId()); |
| HandleCLIError(retcode, sqlci_env); |
| if (retcode > 0) |
| getRowsAffected(cursor->cursorStmtId()); |
| if (donemsg) |
| sprintf(donemsg, OP_COMPLETE_MESSAGE); |
| |
| return 0; |
| } |
| |
| // return of -1 is error, cursor operation was not done. |
| // return of 0 is returned with some cursor/cli operation done. |
| // retcode contains indication if it succeeded(=0) or failed(!= 0) |
| short Cursor::dealloc(SqlciEnv * sqlci_env, char * donemsg, |
| Lng32 &retcode) |
| { |
| CursorStmt * cursor; |
| |
| HandleCLIErrorInit(); |
| |
| retcode = SQL_Success; |
| if (! (cursor = sqlci_env->getCursorList()->get(cursorName_))) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_STMT_NOT_FOUND) |
| << DgString0(cursorName_); |
| return -1; |
| } |
| |
| cleanupCursorStmt(sqlci_env, cursor); |
| |
| if (donemsg) |
| sprintf(donemsg, OP_COMPLETE_MESSAGE); |
| |
| return 0; |
| } |
| |
| // Helper function to do all cleanup when a CursorStmt is no longer |
| // needed. |
| void Cursor::cleanupCursorStmt(SqlciEnv *sqlci_env, CursorStmt *c) |
| { |
| if (!c) |
| return; |
| |
| Lng32 retcode = 0; |
| SQLSTMT_ID *cursorStmtId = c->cursorStmtId(); |
| |
| // Deallocate the underlying SQL statement if this is a stored |
| // procedure result set |
| NABoolean isResultSet = (c->getResultSetIndex() > 0 ? TRUE : FALSE); |
| if (isResultSet && cursorStmtId) |
| { |
| retcode = SQL_EXEC_DeallocStmt(cursorStmtId); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| // The PrepStmt for this cursor should be deallocated if either of |
| // the following are true |
| // - it was internally prepared |
| // (e.g. "declare cursor C for select * from t") |
| // - this is a stored procedure result set |
| |
| PrepStmt *prepStmt = c->prepStmt(); |
| |
| if (prepStmt && (c->internallyPrepared() || isResultSet)) |
| { |
| SQLDESC_ID *sqlSrcDesc = prepStmt->getSqlSrc(); |
| SQLDESC_ID *inDesc = prepStmt->getInputDesc(); |
| SQLDESC_ID *outDesc = prepStmt->getOutputDesc(); |
| SQLSTMT_ID *stmtId = prepStmt->getStmt(); |
| |
| if (sqlSrcDesc) |
| { |
| retcode = SQL_EXEC_DeallocDesc(sqlSrcDesc); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| if (inDesc) |
| { |
| retcode = SQL_EXEC_DeallocDesc(inDesc); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| if (outDesc) |
| { |
| retcode = SQL_EXEC_DeallocDesc(outDesc); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| |
| if (stmtId) |
| { |
| retcode = SQL_EXEC_DeallocStmt(stmtId); |
| HandleCLIError(retcode, sqlci_env); |
| } |
| } |
| |
| // Remove c from the cursor list. This will also call the destructor |
| // for c. |
| sqlci_env->getCursorList()->remove(c->cursorName()); |
| } |
| |
| short Cursor::process(SqlciEnv * sqlci_env) |
| { |
| short rc = 0; |
| |
| if ((NOT internalCursor_) && |
| (! getenv("SQLCI_CURSOR"))) //## rename this to SQL_MXCI_CURSOR ... |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_CURSOR_NOT_SUPPORTED); |
| return 0; |
| } |
| |
| Lng32 retcode = 0; |
| char donemsg[100]; |
| donemsg[0] = '\0'; |
| |
| switch (operation_) |
| { |
| case DECLARE: |
| rc = declareC(sqlci_env, donemsg, retcode); |
| break; |
| |
| case OPEN: |
| rc = open(sqlci_env, donemsg, retcode); |
| break; |
| |
| case FETCH: |
| rc = fetch(sqlci_env, TRUE, donemsg, retcode); |
| break; |
| |
| case CLOSE: |
| rc = close(sqlci_env, donemsg, retcode); |
| break; |
| |
| case DEALLOC: |
| rc = dealloc(sqlci_env, donemsg, retcode); |
| break; |
| } |
| |
| // All the CURSOR methods return 0 or -1. Write the completion |
| // message when (rc == 0). In case of rs==-1, the diags is filled with |
| // error conditions. |
| if (rc == 0) |
| { |
| Logfile *log = sqlci_env->get_logfile(); |
| if (!lastLineWasABlank) log->WriteAll(""); |
| if (donemsg[0] != '\0') log->WriteAll(donemsg); |
| } |
| |
| return 0; |
| } |
| // unified display_qc to display data as follows: |
| // CURSIZE MAXSIZE ENTRIES PLANS LOOKUPS HITS HITRATE |
| // --------- --------- ---------- ---------- ---------- ---------- ------- |
| // 429.49MB 29.49GB 858992 858992 429.496E+7 420.000E+7 97.78% |
| // hit rate = hits / lookups |
| static const char * query_cache_query = |
| " SELECT " |
| " (CASE WHEN CURRENT_SIZE > 1048575 THEN " |
| " CONCAT(RTRIM(CAST(CAST(CURRENT_SIZE/1048576 AS NUMERIC(7,2)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'GB') ELSE " |
| " (CASE WHEN CURRENT_SIZE > 1023 THEN " |
| " CONCAT(RTRIM(CAST(CAST(CURRENT_SIZE/1024 AS NUMERIC(7,2)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'MB') ELSE " |
| " CONCAT(RTRIM(CAST(CURRENT_SIZE AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'KB') " |
| " END) " |
| " END) AS CURSIZE, " |
| " (CASE WHEN MAX_CACHE_SIZE > 1048575 THEN " |
| " CONCAT(RTRIM(CAST(CAST(MAX_CACHE_SIZE/1048576 AS NUMERIC(7,2)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'GB') ELSE " |
| " (CASE WHEN MAX_CACHE_SIZE > 1023 THEN " |
| " CONCAT(RTRIM(CAST(CAST(MAX_CACHE_SIZE/1024 AS NUMERIC(7,2)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'MB') ELSE " |
| " CONCAT(RTRIM(CAST(MAX_CACHE_SIZE AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'KB') " |
| " END) " |
| " END) AS MAXSIZE, " |
| " (CASE WHEN NUM_ENTRIES + TEXT_ENTRIES > 9999999 THEN " |
| " CONCAT(RTRIM(CAST(CAST((NUM_ENTRIES + TEXT_ENTRIES)/10000000 AS NUMERIC(7,3)) " |
| " AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'E+7') ELSE " |
| " CAST(NUM_ENTRIES + TEXT_ENTRIES AS CHAR(7) CHARACTER SET ISO88591) " |
| " END) AS ENTRIES, " |
| " (CASE WHEN NUM_PLANS > 9999999 THEN " |
| " CONCAT(RTRIM(CAST(CAST((NUM_PLANS)/10000000 AS NUMERIC(7,3)) " |
| " AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'E+7') ELSE " |
| " CAST(NUM_PLANS AS CHAR(7) CHARACTER SET ISO88591) " |
| " END) AS PLANS, " |
| " (CASE WHEN NUM_LOOKUPS > 9999999 THEN " |
| " CONCAT(RTRIM(CAST(CAST(NUM_LOOKUPS/10000000 AS NUMERIC(7,3)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'E+7') ELSE " |
| " CAST(NUM_LOOKUPS AS CHAR(7) CHARACTER SET ISO88591) " |
| " END) AS LOOKUPS, " |
| " (CASE WHEN NUM_CACHE_HITS_PARSING + NUM_CACHE_HITS_BINDING + TEXT_CACHE_HITS> 9999999 THEN " |
| " CONCAT(RTRIM(CAST(CAST((NUM_CACHE_HITS_PARSING + NUM_CACHE_HITS_BINDING + " |
| " TEXT_CACHE_HITS)/10000000 AS NUMERIC(7,3)) AS CHAR(7) CHARACTER SET ISO88591)), _ISO88591'E+7') ELSE " |
| " CAST(NUM_CACHE_HITS_PARSING + NUM_CACHE_HITS_BINDING + TEXT_CACHE_HITS AS CHAR(7) CHARACTER SET ISO88591) " |
| " END) AS HITS, " |
| " (CASE WHEN NUM_LOOKUPS <=0 THEN _ISO88591'NA' ELSE " |
| " CONCAT(RTRIM(CAST(CAST(100*(NUM_CACHE_HITS_PARSING + NUM_CACHE_HITS_BINDING + " |
| " TEXT_CACHE_HITS)/NUM_LOOKUPS AS NUMERIC(6,2)) AS CHAR(6) CHARACTER SET ISO88591)), _ISO88591'%') " |
| " END) AS HITRATE " |
| " FROM TABLE(QUERYCACHE()) "; |
| |
| #define SELECT_LIST1 \ |
| " select " \ |
| " (CASE WHEN ROW_ID > 99999999 THEN _ISO88591'OVERFLOW' ELSE " \ |
| " CAST(ROW_ID AS CHAR(8) CHARACTER SET ISO88591) END) AS ROWID, " \ |
| " SUBSTRING(TEXT, 0, 36) AS TEXT, " \ |
| " (CASE WHEN NUM_HITS > 99999999 THEN _ISO88591'OVERFLOW' ELSE " \ |
| " CAST(NUM_HITS AS CHAR(8) CHARACTER SET ISO88591) END) AS NUMHITS, " \ |
| " (CASE PHASE WHEN _ISO88591'PARSING' THEN _ISO88591'P' WHEN _ISO88591'BINDING' THEN _ISO88591'B' ELSE _ISO88591'T' END) AS PH " |
| |
| #define FROMQUERYCACHEENTRIES " from table(querycacheentries()) " |
| |
| static const char * query_cache_ent_query = SELECT_LIST1 |
| ",(CASE WHEN COMPILATION_TIME > 99999999 THEN _ISO88591'OVERFLOW' ELSE " |
| " CAST(COMPILATION_TIME AS CHAR(8) CHARACTER SET ISO88591) END) AS COMPTIME, " |
| |
| " (CASE WHEN AVERAGE_HIT_TIME > 99999999 THEN _ISO88591'OVERFLOW' ELSE " |
| " CAST(AVERAGE_HIT_TIME AS CHAR(8) CHARACTER SET ISO88591) END) AS AVGHTIME " |
| FROMQUERYCACHEENTRIES; |
| |
| static const char * query_cache_ent_query_notime = SELECT_LIST1 |
| FROMQUERYCACHEENTRIES; |
| |
| short QueryCacheSt::process(SqlciEnv * sqlci_env) |
| { |
| Lng32 retcode; |
| DML *query; |
| |
| switch (option_) { |
| case 0: |
| default: |
| { |
| query = new DML(query_cache_query, DML_CONTROL_TYPE); |
| } |
| break; |
| |
| case 1: |
| { |
| query = new DML(query_cache_ent_query, DML_CONTROL_TYPE); |
| } |
| break; |
| |
| case 2: |
| { |
| query = new DML(query_cache_ent_query_notime, DML_CONTROL_TYPE); |
| } |
| break; |
| } |
| |
| retcode = query->process(sqlci_env); |
| |
| if (query) |
| delete query; |
| |
| return (short) retcode; |
| } |
| |
| ////////////////////////////////////////// |
| // begin QUIESCE |
| ////////////////////////////////////////// |
| |
| // Methods for class Quiesce |
| Quiesce::Quiesce() |
| : SqlCmd(SqlCmd::QUIESCE_TYPE, NULL) |
| { |
| } |
| |
| Quiesce::~Quiesce() |
| { |
| } |
| |
| short Quiesce::process(SqlciEnv *sqlci_env) |
| { |
| if (!getenv("SQLCI_CURSOR")) |
| { |
| sqlci_env->diagsArea() << DgSqlCode(-SQLCI_CURSOR_NOT_SUPPORTED); |
| return 0; |
| } |
| |
| Lng32 retcode = SQL_EXEC_Xact(SQLTRANS_QUIESCE, NULL); |
| cout << endl |
| << " SQL_EXEC_Xact(SQLTRANS_QUIESCE, NULL) returned " << retcode |
| << endl << endl; |
| return 0; |
| } |
| |