/**************************************************************************** ** (c) Copyright IBM Corp. 2007 All rights reserved. ** ** The following sample of source code ("Sample") is owned by International ** Business Machines Corporation or one of its subsidiaries ("IBM") and is ** copyrighted and licensed, not sold. You may use, copy, modify, and ** distribute the Sample in any form without payment to IBM, for the purpose of ** assisting you in the development of your applications. ** ** The Sample code is provided to you on an "AS IS" basis, without warranty of ** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR ** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do ** not allow for the exclusion or limitation of implied warranties, so the above ** limitations or exclusions may not apply to you. IBM shall not be liable for ** any damages you suffer as a result of using, copying, modifying or ** distributing the Sample, even if IBM has been advised of the possibility of ** such damages. ***************************************************************************** ** ** SOURCE FILE NAME: tbtemp.sqC ** ** SAMPLE: How to use a declared temporary table ** ** This sample: ** 1. Creates a user temporary table space required for declared ** temporary tables ** 2. Creates and populates a declared temporary table ** 3. Shows that the declared temporary table exists after a commit ** and shows the declared temporary table's use in a procedure ** 4. Shows that the temporary table can be recreated with the same ** name using the "with replace" option and without "not logged" ** clause, to enable logging. ** 5. Shows the creation of an index on the temporary table. ** 6. Show the usage of "describe" command to obtain information ** regarding the tempraroy table. ** 7. Shows the usage of db2RunStats API to to update statistics ** about the physical characteristics of a temp table and the ** associated indexes. ** 8. Shows that the temporary table is implicitly dropped with a ** disconnect from the database ** 9. Drops the user temporary table space ** ** The following objects are made and later removed: ** 1. a user temporary table space named usertemp1 ** 2. a declared global temporary table named temptb1 ** (If objects with these names already exist, an error message ** will be printed out.) ** ** SQL STATEMENTS USED: ** CLOSE ** CREATE USER TEMPORARY TABLESPACE ** CREATE INDEX ** DECLARE CURSOR ** DECLARE GLOBAL TEMPORARY TABLE ** DESCRIBE ** DROP TABLESPACE ** FETCH ** INCLUDE ** INSERT ** OPEN ** PREPARE ** ** DB2 APIs USED: ** db2RunStats ** ** STRUCTURES USED: ** sqlca ** sqlda ** ** ***************************************************************************** ** ** For more information on the sample programs, see the README file. ** ** For information on developing embedded SQL applications see the Developing Embedded SQL Applications book. ** ** For information on using SQL statements, see the SQL Reference. ** ** For the latest information on programming, building, and running DB2 ** applications, visit the DB2 Information Center: ** http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp ****************************************************************************/ #include <stdio.h> #include <string.h> #include <malloc.h> #include <sqlenv.h> #include <sqlcodes.h> #include <sqlutil.h> #include <sqlda.h> #include <db2ApiDf.h> #include "utilemb.h" #if ((__cplusplus >= 199711L) && !defined DB2HP && !defined DB2AIX) || \ (DB2LINUX && (__LP64__ || (__GNUC__ >= 3)) ) #include <iomanip> #include <iostream> using namespace std; #else #include <iomanip.h> #include <iostream.h> #endif // Prototypes: // main // |_CreateTablespace // |_DeclareTempTable // | |_PopulateTempTable // | |_ShowTableContents // |_ShowAfterCommit // | |_ShowTableContents // |_RecreateTempTableWithLogging // | |_PopulateTempTable // | |_ShowTableContents // |_CreateIndex // |_UpdateStatistics // |_DescribeTemporaryTable // | |_NumToAscii // |_DropTablespace EXEC SQL INCLUDE SQLCA; // Variables to store data from the department table EXEC SQL BEGIN DECLARE SECTION; char deptno[4]; char deptname[30]; char mgrno[7]; short mgrnoInd; // use an indicator because null values are possible char admrdept[4]; char location[17]; short locationInd; // use an indicator because null values are possible char strStmt[100]; EXEC SQL END DECLARE SECTION; class TbTemp { public: int CreateTablespace(void); int DeclareTempTable(void); int ShowAfterCommit(void); int DropTablespace(void); int RecreateTempTableWithLogging(void); int CreateIndex(void); int UpdateStatistics(void); int DescribeTemporaryTable(void); private: int PopulateTempTable(void); int ShowTableContents(void); char *NumToAscii(int); }; // Create a user temporary table space for the temporary table. A user // temporary table space is required for temporary tables. This type of // table space is not created at database creation time. int TbTemp::CreateTablespace(void) { cout << "\n-----------------------------------------------------------"; cout << "\nUSE THE SQL STATEMENT:" << endl; cout << " CREATE USER TEMPORARY TABLESPACE " << endl; cout << "TO MAKE A USER TEMPORARY TABLESPACE FOR THE TEMPORARY TABLE\n"; cout << "IN A DIRECTORY CALLED usertemp, RELATIVE TO THE DATABASE\n"; cout << "\n Perform:" << endl; cout << " EXEC SQL CREATE USER TEMPORARY TABLESPACE usertemp1\n"; cout << " MANAGED BY SYSTEM " << endl; cout << " USING ('usertemp')" << endl; EXEC SQL CREATE USER TEMPORARY TABLESPACE usertemp1 MANAGED BY SYSTEM USING ('usertemp'); EMB_SQL_CHECK("create user temporary tablespace"); return sqlca.sqlcode; } // TbTemp::CreateTablespace // Declare a temporary table with the same columns as the one for the // database's department table. Populate the temporary table and // show the contents. int TbTemp::DeclareTempTable(void) { int rc = 0; // Declare the declared temporary table. It is created empty. cout << "\n-----------------------------------------------------------"; cout << "\nUSE THE SQL STATEMENT:" << endl; cout << " DECLARE GLOBAL TEMPORARY TABLE" << endl; cout << "TO MAKE A GLOBAL DECLARED TEMPORARY TABLE WITH THE SAME" << endl; cout << "COLUMNS AS THE DEPARTMENT TABLE." << endl; cout << "\n Perform:" << endl; cout << " EXEC SQL DECLARE GLOBAL TEMPORARY TABLE temptb1 " << endl; cout << " LIKE department " << endl; cout << " NOT LOGGED" << endl; EXEC SQL DECLARE GLOBAL TEMPORARY TABLE temptb1 LIKE department NOT LOGGED; EMB_SQL_CHECK("declare global temporary table"); rc = sqlca.sqlcode; if (rc != 0) { return rc; } rc = PopulateTempTable(); if (rc != 0) { return rc; } rc = ShowTableContents(); return rc; } // TbTemp::DeclareTempTable // Show that the temporary table still exists after the commit. All the // rows will be deleted because the temporary table was declared, by default, // with "on commit delete rows". If "on commit preserve rows" was used, // then the rows would have remained. int TbTemp::ShowAfterCommit(void) { int rc = 0; cout << "\n-----------------------------------------------------------"; cout << "\nUSE THE SQL STATEMENT:" << endl; cout << " COMMIT" << endl; cout << "TO SHOW THAT THE TEMP TABLE EXISTS AFTER A COMMIT BUT WITH\n"; cout << "ALL ROWS DELETED" << endl; cout << "\n Perform:" << endl; cout << " EXEC SQL COMMIT" << endl; EXEC SQL COMMIT; EMB_SQL_CHECK("commit"); rc = sqlca.sqlcode; if (rc != 0) { return rc; } rc = ShowTableContents(); return rc; } // TbTemp::ShowAfterCommit // Declare the temp table temptb1 again this time with logging option, // thereby replacing the existing one. If the "with replace" option is // not used, then an error will result if the table name is already // associated with an existing temporary table. Populate and show the // contents again. int TbTemp::RecreateTempTableWithLogging(void) { int rc = 0; // Declare the declared temporary table again, this time without the // NOT LOGGED clause. It is created empty. cout << "\n-----------------------------------------------------------"; cout << "\nUSE THE SQL STATEMENT:" << endl; cout << " DECLARE GLOBAL TEMPORARY TABLE" << endl; cout << "TO REPLACE A GLOBAL DECLARED TEMPORARY TABLE WITH A NEW" << endl; cout << "TEMPORARY TABLE OF THE SAME NAME WITH LOGGING ENABLED." << endl; cout << "\n Perform:" << endl; cout << " EXEC SQL DECLARE GLOBAL TEMPORARY TABLE temptb1 " << endl; cout << " LIKE department " << endl; cout << " WITH REPLACE" << endl; cout << " ON COMMIT PRESERVE ROWS" << endl; EXEC SQL DECLARE GLOBAL TEMPORARY TABLE temptb1 LIKE department WITH REPLACE ON COMMIT PRESERVE ROWS; EMB_SQL_CHECK("declare global temporary table with replace"); rc = sqlca.sqlcode; if (rc != 0) { return rc; } rc = PopulateTempTable(); if (rc != 0) { return rc; } rc = ShowTableContents(); return sqlca.sqlcode; } // TbTemp::RecreateTempTableWithLogging // Create Index command can be used on temporary tables to improve // the performance of queries int TbTemp::CreateIndex(void) { cout << "\n-----------------------------------------------------------"; cout << "\n Indexes can be created for temporary tables. Indexing a table\n"; cout << " optimizes query performance " << endl; cout << "\n CREATE INDEX session.tb1ind " << endl; cout << " ON session.temptb1 (deptno DESC) " << endl; cout << " DISALLOW REVERSE SCANS " << endl; EXEC SQL CREATE INDEX session.tb1ind ON session.temptb1(deptno DESC) DISALLOW REVERSE SCANS; cout << "\n Following clauses in create index are not supported " << endl; cout << " for temporary tables:" << endl; cout << " SPECIFICATION ONLY" << endl; cout << " CLUSTER" << endl; cout << " EXTEND USING" << endl; cout << " Option SHRLEVEL will have no effect when creating indexes " << endl; cout << " on DGTTs and will be ignored " << endl; cout << "\n Indexes can be dropped by issuing DROP INDEX statement, " << endl; cout << " or they will be implicitly dropped when the underlying temp " << endl; cout << " table is dropped." << endl; return sqlca.sqlcode; } // TbTemp::CreateIndex // db2RunStats updates statistics about the characteristics of the temp // table and/or any associated indexes. These characteristics include, // among many others, number of records, number of pages, and average // record length. int TbTemp::UpdateStatistics(void) { struct sqlca sqlca; char fullTableName[258]; db2Uint32 versionNumber = db2Version970; db2RunstatsData runStatData; cout << "\n-----------------------------------------------------------"; cout << "\nUSE THE DB2 API:" << endl; cout << " db2Runstats -- Runstats" << endl; cout << "TO UPDATE session.temptb1 STATISTICS." << endl; strcpy(fullTableName, "session.temptb1"); // runstats table runStatData.iSamplingOption = 0; runStatData.piTablename = ( unsigned char *) fullTableName; runStatData.piColumnList = NULL; runStatData.piColumnDistributionList = NULL; runStatData.piColumnGroupList = NULL; runStatData.piIndexList = NULL; runStatData.iRunstatsFlags = DB2RUNSTATS_ALL_INDEXES; runStatData.iNumColumns = 0; runStatData.iNumColdist = 0; runStatData.iNumColGroups = 0; runStatData.iNumIndexes = 0; runStatData.iParallelismOption = 0; runStatData.iTableDefaultFreqValues = 0; runStatData.iTableDefaultQuantiles = 0; runStatData.iUtilImpactPriority = 100; db2Runstats (versionNumber, &runStatData, &sqlca); DB2_API_CHECK("table -- runstats"); cout << "\n Viewing of runstat data on declared temporary tables or" << endl; cout << " indexes on declared temporary tables is not supported" << endl; return sqlca.sqlcode; } // TbTemp::UpdateStatistics // Use the Describe Command to describe the temporary table created. // DESCRIBE TABLE command cannot be used with temp table.However, // DESCRIBE statement can be used with SELECT statement to get // table information. */ int TbTemp::DescribeTemporaryTable(void) { int i; struct sqlca sqlca; struct sqlda *pSqlda = (struct sqlda *)new char[SQLDASIZE(6)]; cout << "\n-----------------------------------------------------------"; cout << "\n Use the DESCRIBE COMMAND to describe temporary table" << endl; strcpy(strStmt, "SELECT * FROM session.temptb1"); cout << "\n Perform:" << endl; cout << "\n DESCRIBE SELECT * FROM session.temptb1" << endl; pSqlda->sqln = 6; // prepare the select statement EXEC SQL PREPARE stmt FROM :strStmt; EMB_SQL_CHECK("statement -- prepare"); // Information regarding the SELECT statement is fetched into // the sqlda structure variable EXEC SQL DESCRIBE stmt INTO :*pSqlda; EMB_SQL_CHECK("statement -- describe"); // Display the contents of the sqlda structure cout << "\nSQLDA Information" << endl; cout << "\n sqldaid: SQLDA sqldabc: "<< pSqlda->sqldabc << " sqln: " << pSqlda->sqln << " sqld: " << pSqlda->sqld <<endl; cout << "\n Column Information\n\n"; cout <<" sqltype sqllen sqlname.data sqlname.length\n"; cout <<" --------------- ------ ------------------- --------------\n"; for(i = 0; i < pSqlda->sqld ; i++) { cout.setf(ios::right, ios::adjustfield); cout << endl << " " << setw(4) << pSqlda->sqlvar[i].sqltype; cout.setf(ios::left, ios::adjustfield); cout << " " << setw(10) << NumToAscii(pSqlda->sqlvar[i].sqltype); cout.setf(ios::right, ios::adjustfield); cout << " " << setw(6) << pSqlda->sqlvar[i].sqllen << " "; cout.setf(ios::left, ios::adjustfield); cout << setw(19) << pSqlda->sqlvar[i].sqlname.data ; cout.setf(ios::right, ios::adjustfield); cout << setw(14) << pSqlda->sqlvar[i].sqlname.length ; } cout << endl; delete [] pSqlda; return sqlca.sqlcode; } // TbTemp::DescribeTemporaryTable // Populate the temporary table with the department table's contents. int TbTemp::PopulateTempTable(void) { // Populating the temporary table is done the same way as a normal table // except the qualifier "session" is required whenever the table name // is referenced. cout << "\nUSE THE SQL STATEMENT:" << endl; cout << " INSERT" << endl; cout << "TO POPULATE THE DECLARED TEMPORARY TABLE WITH DATA FROM" << endl; cout << "THE DEPARTMENT TABLE" << endl; cout << "\n Perform:" << endl; cout << " EXEC SQL INSERT INTO session.temptb1" << endl; cout << " (SELECT deptno, deptname, mgrno, admrdept, location\n"; cout << " FROM department)" << endl; EXEC SQL INSERT INTO session.temptb1 (SELECT deptno, deptname, mgrno, admrdept, location FROM department); EMB_SQL_CHECK("insert"); return sqlca.sqlcode; } // TbTemp::PopulateTempTable // Use cursors to access each row of the declared temporary table and then // print each row. This function assumes that the declared temporary table // exists. This access is the same as accessing a normal table except the // qualifier, "session", is required in the table name. int TbTemp::ShowTableContents(void) { cout <<"\n SELECT * FROM session.temptb1" << endl; cout << " DEPT# DEPTNAME MGRNO ADMRDEPT LOCATION" << endl; cout << " ----- ---------------------------- ------ -------- --------" << endl; // Declare cursor EXEC SQL DECLARE c1 CURSOR FOR SELECT * FROM session.temptb1; // Open cursor EXEC SQL OPEN c1; EMB_SQL_CHECK("cursor -- open"); // Fetch cursor EXEC SQL FETCH c1 INTO :deptno, :deptname, :mgrno :mgrnoInd, /* null value indicator */ :admrdept, :location :locationInd; /* null value indicator */ EMB_SQL_CHECK("cursor -- fetch"); while (sqlca.sqlcode != 100) { if (mgrnoInd < 0) { // the manager number was a null value so print a hyphen instead sprintf(mgrno, "-"); } if (locationInd < 0) { // the location was a null value so print a hyphen instead sprintf(location, "-"); } cout.setf(ios::left, ios::adjustfield); cout << " " << setw(5) << deptno; cout.setf(ios::left, ios::adjustfield); cout << " " << setw(28) << deptname; cout.setf(ios::left, ios::adjustfield); cout << " " << setw(6) << mgrno; cout.setf(ios::left, ios::adjustfield); cout << " " << setw(8) << admrdept; cout.setf(ios::left, ios::adjustfield); cout << " " << setw(8) << location; cout.setf(ios::right, ios::adjustfield); cout << endl; EXEC SQL FETCH c1 INTO :deptno, :deptname, :mgrno :mgrnoInd, /* null value indicator */ :admrdept, :location :locationInd; /* null value indicator */ EMB_SQL_CHECK("cursor -- fetch"); } // Close cursor EXEC SQL CLOSE c1; EMB_SQL_CHECK("cursor -- close"); return 0; } // TbTemp::ShowTableContents // Drop the user temporary table space. This function assumes that the // table space can be dropped. If the declared temporary table still exists // in the table space, then the table space cannot be dropped. int TbTemp::DropTablespace(void) { cout << "\n-----------------------------------------------------------"; cout << "\nUSE THE SQL STATEMENT:" << endl; cout << " DROP TABLESPACE " << endl; cout << "TO REMOVE THE TABLE SPACE THAT THIS PROGRAM CREATED" << endl; cout << "\n Perform:" << endl; cout << " EXEC SQL DROP TABLESPACE usertemp1" << endl; EXEC SQL DROP TABLESPACE usertemp1; EMB_SQL_CHECK("drop tablespace"); return sqlca.sqlcode; } // TbTemp::DropTablespace // DESCRIBE command returns the statement information in SQLDA structure. // SQLTYPE field is returned as an integer and has to be mapped to the // sql type name */ char * TbTemp::NumToAscii(int sqlTypeNum) { char * sqlTypeName = (char*)malloc(12 * sizeof(char)); switch(sqlTypeNum) { case 384 : case 385 : strcpy(sqlTypeName, "DATE"); break; case 388 : case 389 : strcpy(sqlTypeName, "TIME"); break; case 392 : case 393 : strcpy(sqlTypeName, "TIMESTAMP"); break; case 448 : case 449 : strcpy(sqlTypeName, "VARCHAR"); break; case 452 : case 453 : strcpy(sqlTypeName, "CHARACTER"); break; case 480 : case 481 : strcpy(sqlTypeName, "FLOAT"); break; case 484 : case 485 : strcpy(sqlTypeName, "DECIMAL"); break; case 496 : case 497 : strcpy(sqlTypeName, "INTEGER"); break; case 500 : case 501 : strcpy(sqlTypeName, "SMALLINT"); break; default : strcpy(sqlTypeName, "UNKNOWN TYPE"); } return sqlTypeName; } // TbTemp::NumToAscii int main(int argc, char *argv[]) { int rc = 0; char dbAlias[SQL_ALIAS_SZ + 1]; char user[USERID_SZ + 1]; char pswd[PSWD_SZ + 1]; CmdLineArgs check; DbEmb db; TbTemp temp; // Check the command line arguments rc = check.CmdLineArgsCheck1(argc, argv, db); if (rc != 0) { return rc; } cout << "\nTHIS SAMPLE SHOWS HOW TO USE DECLARED TEMPORARY TABLES." <<endl; // Connect to database cout << "\n-----------------------------------------------------------"; rc = db.Connect(); if (rc != 0) { return rc; } // Make sure a user temporary table space exists before creating the // table temp.CreateTablespace(); // Show how to make a declared temporary table temp.DeclareTempTable(); // Show that the temporary table exists in ShowAfterCommit() even though // it was declared in DeclareTempTable(). The temporary table is // accessible to the whole session as the connection still exists at this // point. Show that the temporary table exists after a commit. temp.ShowAfterCommit(); // Declare the temporary table again. The old one will be dropped and a // new one will be made. temp.RecreateTempTableWithLogging(); // Create an index for the global temporary table temp.CreateIndex(); // Update temporary table statistics using db2RunStats temp.UpdateStatistics(); // Use the Describe Command to describe the temp table temp.DescribeTemporaryTable(); // Disconnect from the database. This implicitly drops the temporary table. // Alternatively, an explicit drop statement could have been used. cout << "\n-----------------------------------------------------------"; rc = db.Disconnect(); if (rc != 0) { return rc; } cout << "THE DECLARED TEMPORARY TABLE IS IMPLICITLY DROPPED." << endl; // Connect to database cout << "\n-----------------------------------------------------------"; rc = db.Connect(); if (rc != 0) { return rc; } // Clean up - remove the table space that was created earlier. // Note: The table space can only be dropped after the temporary table is // dropped. temp.DropTablespace(); // Disconnect from the database cout << "\n-----------------------------------------------------------"; rc = db.Disconnect(); if (rc != 0) { return rc; } return rc; } // main