SQLMoreResults() - Check for more result sets

SQLMoreResults() returns more information about a statement handle. The information can be associated with an array of input parameter values for a query, or a stored procedure that returns results sets.

ODBC specifications for SQLMoreResults()

Table 1. SQLMoreResults() specifications
ODBC specification level In X/Open CLI CAE specification? In ISO CLI specification?
1.0 No No

Syntax

SQLRETURN   SQLMoreResults   (SQLHSTMT          hstmt);

Function arguments

The following table lists the data type, use, and description for each argument in this function.

Table 2. SQLMoreResults() arguments
Data type Argument Use Description
SQLHSTMT hstmt input Specifies the statement handle on which results are returned.

Usage

Use this function to return a sequence of result sets after you execute of one of the following actions:
  • A parameterized query with an array of input parameter values that SQLSetStmtAttr() and SQLBindParameter() specify
  • A stored procedure that contains SQL queries that leaves open cursors on the result sets that it generates (result sets are accessible when a stored procedure has finished execution if cursors on these result sets remain open)

After you completely process a result set, call SQLMoreResults() to determine if another result set is available. When you call SQLMoreResults(), this function discards rows that were not fetched in the current result set by closing the cursor. If another result set is available SQLMoreResults() returns SQL_SUCCESS.

If all the result sets have been processed, SQLMoreResults() returns SQL_NO_DATA_FOUND.

If you call SQLFreeStmt() with the fOption argument set to SQL_CLOSE or you call SQLFreeHandle() is called with the HandleType argument set to SQL_HANDLE_STMT, these functions discard all pending result sets for the statement handle on which they are called.

Return codes

After you call SQLMoreResults(), it returns one of the following values:
  • SQL_SUCCESS
  • SQL_SUCCESS_WITH_INFO
  • SQL_ERROR
  • SQL_INVALID_HANDLE
  • SQL_NO_DATA_FOUND

Diagnostics

The following table lists each SQLSTATE that this function generates, with a description and explanation for each value.

Table 3. SQLMoreResults() SQLSTATEs
SQLSTATE Description Explanation
08S01 Communication link failure. The communication link between the application and data source fails before the function completes.
58004 Unexpected system failure. Unrecoverable system error.
HY001 Memory allocation failure. Db2 ODBC is not able to allocate the required memory to support the execution or the completion of the function.
HY010 Function sequence error. The function is called during a data-at-execute operation. (That is, the function is called during a procedure that uses the SQLParamData() or SQLPutData() functions.)
HY013 Unexpected memory handling error. Db2 ODBC is not able to access the memory that is required to support execution or completion of the function.

Additionally, SQLMoreResults() can return all SQLSTATEs that are associated with SQLExecDirect() except for HY009, HY014, and HY090.

Restrictions

The ODBC specification of SQLMoreResults() allows row-counts that are associated with the execution of parameterized INSERT, UPDATE, and DELETE statements with arrays of input parameter values to be returned. However, Db2 ODBC does not support the return of this count information.

Example

The following example shows an application that uses SQLMoreResults() to check for additional result sets.
Figure 1. An application that checks for additional result sets
/* ... */
#define NUM_CUSTOMERS 25
    SQLCHAR         stmt[] =
    {  "WITH "  /* Common Table expression (or Define Inline View) */
         "order (ord_num, cust_num, prod_num, quantity, amount) AS "
         "( "
         "SELECT c.ord_num, c.cust_num, l.prod_num, l.quantity,  "
                 "price(char(p.price, '.'), p.units, char(l.quantity, '.')) "
            "FROM ord_cust c, ord_line l, product p  "
            "WHERE c.ord_num = l.ord_num AND l.prod_num = p.prod_num  "
             "AND cust_num = CNUM(cast (? as integer)) "
         "), "
         "totals (ord_num, total) AS "
         "( "
          "SELECT ord_num, sum(decimal(amount, 10, 2))  "
          "FROM order GROUP BY ord_num "
         ") "
       /* The 'actual' SELECT from the inline view */
       "SELECT order.ord_num, cust_num, prod_num, quantity,  "
              "DECIMAL(amount,10,2) amount, total "
        "FROM order, totals  "
        "WHERE order.ord_num = totals.ord_num "
     };
    /* Array of customers to get list of all orders for */
    SQLINTEGER     Cust[]=
    {
        10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
        110, 120, 130, 140, 150, 160, 170, 180, 190, 200,
        210, 220, 230, 240, 250
    };
#define  NUM_CUSTOMERS sizeof(Cust)/sizeof(SQLINTEGER)
    /* Row-wise (Includes buffer for both column data and length) */
    struct {
        SQLINTEGER      Ord_Num_L;
        SQLINTEGER      Ord_Num;
        SQLINTEGER      Cust_Num_L;
        SQLINTEGER      Cust_Num;
        SQLINTEGER      Prod_Num_L;
        SQLINTEGER      Prod_Num;
        SQLINTEGER      Quant_L;
        SQLDOUBLE       Quant;
        SQLINTEGER      Amount_L;
        SQLDOUBLE       Amount;
        SQLINTEGER      Total_L;
        SQLDOUBLE       Total;
    }               Ord[ROWSET_SIZE];
    SQLUINTEGER     pirow = 0;
    SQLUINTEGER     pcrow;
    SQLINTEGER      i;
    SQLINTEGER      j;
/* ... */
    /* Get details and total for each order row-wise */
    rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
    rc = SQLParamOptions(hstmt, NUM_CUSTOMERS, &pirow);
    rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
                          0, 0, Cust, 0, NULL);
    rc = SQLExecDirect(hstmt, stmt, SQL_NTS);
    /* SQL_ROWSET_SIZE sets the max number of result rows to fetch each time */
    rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROWSET_SIZE, ROWSET_SIZE, 0);
    /* Set size of one row, used for row-wise binding only */
    rc = SQLSetStmtAttr(hstmt, SQL_ATTR_BIND_TYPE, (void*)sizeof(Ord)/ROW_SIZE, 0);
    /* Bind column 1 to the Ord_num Field of the first row in the array*/
    rc = SQLBindCol(hstmt, 1, SQL_C_LONG, (SQLPOINTER) &Ord[0].Ord_Num, 0,
                    &Ord[0].Ord_Num_L);
    /* Bind remaining columns ... */
/* ... */
    /* NOTE: This sample assumes that an order never has more
             rows than ROWSET_SIZE.  A check should be added below to call
             SQLExtendedFetch multiple times for each result set.
    */
    do  /* for each result set .... */
    { rc = SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 0, &pcrow, NULL);
      if (pcrow > 0) /* if 1 or more rows in the result set */
      {
        i = j = 0;
        printf("**************************************\n");
        printf("Orders for Customer: %ld\n", Ord[0].Cust_Num);
        printf("**************************************\n");
        while (i < pcrow)
        {   printf("\nOrder #: %ld\n", Ord[i].Ord_Num);
            printf("     Product  Quantity         Price\n");
            printf("     -------- ---------------- ------------\n");
            j = i;
            while (Ord[j].Ord_Num == Ord[i].Ord_Num)
            {   printf("    %8ld %16.7lf %12.2lf\n",
                       Ord[i].Prod_Num, Ord[i].Quant, Ord[i].Amount);
                i++;
            }
            printf("                                        ============\n");
            printf("                                       %12.2lf\n", Ord[j].Total);
        } /* end while */
      } /* end if */
    }
    while ( SQLMoreResults(hstmt) == SQL_SUCCESS);
/* ... */