/**********************************************************************
* FILENAME :        ReadingMultipleLongTextFields.c
*
* DESCRIPTION :
*		This example retrieves data fram a choice of tables but shows
*               how to handle more than one long text fields in the record (i.e.
*               in the case of TestTBL4 which has LONGVARCHAR fields Memo1 and
*               Memo2).
*
* ODBC USAGE :
*		Prompts for table number to get table name
*               Formats select based on table columns
*		SQLExecDirect to execute SELECT statement
*		SQLFetch to get the next rowset
*		SQLGetData to retrieve the data for all but long text fields
*		SQLGetData to return text data on each long text field
*               until SQL_NO_DATA
*/
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqlext.h>
#include <string.h>

#include "util.c"

#define NAMELEN 30
#define BIRTHDAYLEN 256
#define M1DATASIZE  520+1 // How much of the Memo1 to read in one go
#define M2DATASIZE  520+1 // How much of the Memo2 to read in one go

#define PERSONID_LEN  2
#define LASTNAME_LEN  255
#define FIRSTNAME_LEN 255
#define ADDRESS_LEN 255
#define CITY_LEN  255

#define TRUE 1

int main () {

    SQLHENV  henv  = SQL_NULL_HENV;   // Environment
    SQLHDBC  hdbc  = SQL_NULL_HDBC;   // Connection handle
    SQLHSTMT hstmt = SQL_NULL_HSTMT;  // Statement handle

    SQLRETURN retcode;

    SQLINTEGER colNo;

    SQLUINTEGER PersonID;
    SQLCHAR FirstName[LASTNAME_LEN];
    SQLCHAR LastName[FIRSTNAME_LEN];
    SQLCHAR Address[ADDRESS_LEN];
    SQLCHAR City[CITY_LEN];

    SQLLEN siPersonID, siFirstName, siLastName, siAddress, siCity;

    SQLCHAR	name[NAMELEN];
    SQLINTEGER age;
    SQLCHAR birthday[BIRTHDAYLEN];
    SQLCHAR Memo1[M1DATASIZE];
    SQLCHAR Memo2[M2DATASIZE];

    SQLLEN      siname, siage, sibirthday, siMemo1, siMemo2;
    SQLSMALLINT	status, statuslen;

    char sqlStatement[5][256]= {
    {"SELECT PersonID, FirstName, LastName, Address, City FROM TestTBL1"},
    {"SELECT PersonID, FirstName, LastName, Address, City FROM TestTBL1Copy"},
    {"SELECT FirstName, LastName, Address, City FROM TestTBL2"},
    {"SELECT NAME, AGE, BIRTHDAY, Memo1 FROM TestTBL3"},
    {"SELECT NAME, AGE, BIRTHDAY, Memo1, Memo2 FROM TestTBL4"}
	};

    int tableNo=-1;

    // Loop round tables until 0 (quit) entered
	while (tableNo != 0) {
		getInt ("\nWhich Table"
                "\n0 (Quit)"
                "\n1 (TestTBL1 ID)"
                "\n2 (TestTBL1Copy ID)"
                "\n3 (TestTBL2 NoID)"
                "\n4 (TestTBL3 Memo1)"
                "\n5 (TestTBL4 Memo1, Memo2)"
                "\n  ? ", &tableNo, 'N', 0);
		if (tableNo==0 ||
            (tableNo!=1 && tableNo!=2 && tableNo!=3 && tableNo!=4))
			goto exit;

	    printf ("\n");

	    // Allocate the ODBC environment and save handle.
	    retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
	    CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_ENV)",
                    henv, SQL_HANDLE_ENV);

	    // Notify ODBC that this is an ODBC 3.0 app.
	    retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
                                            (SQLPOINTER) SQL_OV_ODBC3, 0);
	    CHECK_ERROR(retcode, "SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)",
                                            henv, SQL_HANDLE_ENV);

	    // Allocate ODBC connection handle and connect.
	    retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
            CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_DBC)",
                    hdbc, SQL_HANDLE_DBC);

            // Connect to the DSN
	    retcode=SQLDriverConnect(hdbc, NULL, "DSN=DATASOURCE;",
                            SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
	    CHECK_ERROR(retcode, "SQLDriverConnect(DSN=DATASOURCE;)",
                    hdbc, SQL_HANDLE_DBC);

	    // Allocate statement handle.
	    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
	    CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)",
                    hdbc, SQL_HANDLE_STMT);

	    // Execute the command.
	    retcode = SQLExecDirect(hstmt, &sqlStatement[tableNo-1][0], SQL_NTS);
	    CHECK_ERROR(retcode, "SQLExecDirect()", hstmt, SQL_HANDLE_STMT);

            // Call SQLFetch until SQL_NO_DATA (or error) is returned
		while (TRUE) {
			retcode = SQLFetch(hstmt);
			if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) {
				extract_error("SQLFetch(hstmt)", hstmt, SQL_HANDLE_STMT);
	            goto exit;
			}

	        if (retcode == SQL_NO_DATA) {
	            break;
	        }

	        if (retcode == SQL_SUCCESS){
	            switch (tableNo)
	            {
	                case 1:        // TestTBL1 Has PersonID identity column
	                case 2:        // TestTBL2 Has no PersonID identity Column
	            		memset (FirstName, ' ', FIRSTNAME_LEN);
	            		memset (LastName, ' ', LASTNAME_LEN);
	            		memset (Address, ' ', ADDRESS_LEN);
	            		memset (City, ' ', CITY_LEN);
						colNo=1;

						// If table 1, 1st field is PersonID identity field
						if (tableNo==1) {
		            		retcode = SQLGetData(hstmt, colNo++, SQL_C_ULONG,
                                                    &PersonID, 0, &siPersonID);
						}

						// Common fields in both Table1 and Table2
						retcode = SQLGetData(hstmt, colNo++, SQL_C_CHAR,
                                    FirstName, FIRSTNAME_LEN, &siFirstName);
	             		retcode = SQLGetData(hstmt, colNo++, SQL_C_CHAR,
                                    LastName, LASTNAME_LEN, &siLastName);
	            		retcode = SQLGetData(hstmt, colNo++, SQL_C_CHAR,
                                    Address, ADDRESS_LEN, &siAddress);
	            		retcode = SQLGetData(hstmt, colNo++, SQL_C_CHAR,
                                    City, CITY_LEN, &siCity);

	                    // Print the record
	                    if (tableNo==1) {
	                        printf("%i, %.10s, %.10s, %.10s, %.10s\n",
                                        PersonID, FirstName, LastName, Address, City);
	                    } else {
	                        printf("%.10s, %.10s, %.10s, %.10s\n",
                                                  FirstName, LastName, Address, City);
	                    }
	                    break;

	                case 3:     // TestTBL3 has 1 text field Memo1
	                case 4:     // TestTBL4 has 2 text fields Memo1 and Memo2
	            		memset (name, ' ', NAMELEN);
	            		memset (birthday, ' ', BIRTHDAYLEN);

						// Common fields in both Table3 and Table4
	            		retcode = SQLGetData(hstmt, 1, SQL_C_CHAR,
                                                    name, NAMELEN, &siname);
	            		retcode = SQLGetData(hstmt, 2, SQL_C_ULONG,
                                                    &age, 0, &siage);
	            		retcode = SQLGetData(hstmt, 3, SQL_C_CHAR,
                                                    birthday, BIRTHDAYLEN,
                                                    &sibirthday);

						// Tables 3 and 4 have text field Memo1 in column 4.
                        // Read until SQL_NO_DATA ...
	            		do {
	            			memset (Memo1, ' ', sizeof (Memo1));
	            			retcode = SQLGetData(hstmt, 4, SQL_CHAR, Memo1,
                                                            M1DATASIZE, &siMemo1);
	            		} while (retcode == SQL_SUCCESS_WITH_INFO &&
                                    SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 1, 4,
                                                    &status,
                                                    SQL_INTEGER, &statuslen)
                                    != SQL_NO_DATA);

						// Table4 has second text field Memo2 in column 5.
                        // Read until SQL_NO_DATA ...
	                    if (tableNo==4) {
	                        do {
	                        	memset (Memo2, ' ', sizeof (Memo2));
	                        	retcode = SQLGetData(hstmt, 5, SQL_CHAR,
                                                     Memo2, M2DATASIZE,
                                                     &siMemo2);
	                        } while (retcode == SQL_SUCCESS_WITH_INFO &&
                                        SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 1,
                                                        5, &status, SQL_INTEGER,
                                                        &statuslen)
                                        != SQL_NO_DATA);
	                    }

	                    // Print the record
	                    if (tableNo==3) {
	                        printf("%.10s, %i, %.10s, %.10s\n",
                                            name, age, birthday, Memo1);
	                    } else {
	                        printf("%.10s, %i, %.10s, %.10s, %.10s\n",
                                            name, age, birthday, Memo1, Memo2);
	                    }
	                    break;
	                default:
	                    break;
	            }
	        }
		}
	}

    printf ("\nComplete.\n");

exit:

	if (hstmt!=SQL_NULL_HSTMT) {
        SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
		hstmt = SQL_NULL_HSTMT;
	}

    if (hdbc!=SQL_NULL_HDBC) {
        SQLDisconnect(hdbc);
        SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
		hdbc = SQL_NULL_HDBC;
    }

    if (henv!=SQL_NULL_HENV) {
		SQLFreeHandle(SQL_HANDLE_ENV, henv);
		hstmt = SQL_NULL_HSTMT;
    }

    return 0;
}

Further information