/****************************************************************************
** (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: dtstruct.sqC
**
** SAMPLE: Create, use, drop a hierarchy of structured types and typed tables
**
**         This sample program demonstrates how to create structured types
**         and typed tables using SQL. The program creates a hierarchy
**         of structured types and then a hierarchy of typed tables
**         that is defined by the hierarchy of structured types.  It also
**         shows how to insert data into the typed tables. The sample 
**         demonstrates how to use some typed table clauses, such as ONLY
**         and OUTER, and to update the data in a typed table. It compares
**         different ways to retrieve data using structured type features.

**         This sample program also demonstrates how to drop a hierachy of
**         structured types and a hierarchy of typed tables using SQL. The
**         program drops the hierarchy of typed tables first, then it drops
**         the hierarchy of structured types.
**
**
** SQL STATEMENTS USED:
**         CREATE TYPE
**         CREATE TABLE
**         ALTER TYPE
**         ALTER TABLE
**         INSERT
**         SELECT
**         UPDATE
**         DROP TYPE
**         DROP TABLE
**         EXECUTE IMMEDIATE
**
** STRUCTURES USED:
**          sqlca
**
**                           
*****************************************************************************
**
** 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, compiling, and running DB2
** applications, visit the DB2 Information Center at
**     http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp
****************************************************************************/

#include <string.h>
#include <stdio.h>
#include <sqlenv.h>
#include <sqlca.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


EXEC SQL INCLUDE SQLCA;


class structtype
{
  public:
    int CreateStructTypes();
    int CreateTypedTables();
    int AlterStructType(char *stmt);
    int PopulateTbls();
    int InsertPerson(int id, char *name, char *year);
    int InsertEmp(int id, char *name, char *birthYear,
                int salary, int deptID);
    int InsertEmp(int id, char *name);
    int InsertStudent(int id, char *name, char *birthYear,
                char *major, double archivm);
    int InsertProf(int id, char *name, char *birthYear,
                int salary, char *speciality, int dept);
    int InsertDept(int id, char *name, int budget, int mgrId);

    int ComparePersonEmpContents();
    int ShowOnlyOuterEmp();
    int ShowEmpsDept();
    int ShowMgrEmps(char *mgr);
    int UptPersonBirth(int birthYear, int id);

    int DropStructTables();
    int DropStructTypes();

  private:
    int ExecuteStmt(char *stmt);
    int DropTypeOrTable(char *objName, int objType);
};

static const int DROP_TYPE  = 1;
static const int DROP_TABLE = 2;


int main (int argc, char *argv[])
{
  cout << "\nSample C++ program : dtstruct.sqC\n\n" << endl;
  cout << "THIS SAMPLE SHOWS HOW TO CREATE AND USE STRUCTURED TYPES AND TYPED "
       << "TABLES" << endl;

  int rc = 0;
  structtype aStType;
  struct sqlca sqlca;
  CmdLineArgs check;
  DbEmb db;

  // check the command line arguments
  rc = check.CmdLineArgsCheck1(argc, argv, db);
  if (rc != 0)
  {
    return rc;
  }

  // connect to the database
  rc = db.Connect();
  if (rc != 0)
  {
    return rc;
  }

  // Setup the structured types and tables.  As well as populate the database
  rc = aStType.CreateStructTypes();
  if (rc != 0) return rc;

  // Create structured tables
  rc = aStType.CreateTypedTables();
  if (rc != 0) return rc;

  //Populate the database
  rc = aStType.PopulateTbls();
  if (rc != 0) return rc;

  // Use the structured types and tables.
  cout << "\n----------------------------------------" << endl;
  cout << "USE THE SQL STATEMENT:\n"
       << " SELECT\n"
       << "TO RETRIEVE TABLE DATA\n" << endl;

  //Compare root table with subtable
  rc = aStType.ComparePersonEmpContents();
  if (rc != 0) return rc;

  cout << "\n----------------------------------------" << endl;
  cout << "USE THE SQL STATEMENT:\n"
       << " UPDATE\n"
       << "TO MODIFY TABLE DATA\n" << endl;
  rc = aStType.UptPersonBirth(1964, 30);
  if (rc != 0) return rc;

  //Demonstrate ONLY and OUTER
  rc = aStType.ShowOnlyOuterEmp();
  if (rc != 0) return rc;

  //Select name and dept name for all employees
  rc = aStType.ShowEmpsDept();
  if (rc != 0) return rc;

  //Select employees whose manager's manager is Lou
  rc = aStType.ShowMgrEmps("Lou");
  if (rc != 0) return rc;

  // Drop the structured types and tables.
  rc = aStType.DropStructTables();
  if (rc != 0) return rc;

  //Drop the structured types
  rc = aStType.DropStructTypes();
  if (rc != 0) return rc;

  //Disconnect from database
  db.Disconnect();

  return 0;

} // end of main


int structtype::CreateStructTypes()
{
  int rc = 0;
  char aStmt[140];

  cout << "\n-----------------------------------------------" << endl;
  cout << "USE THE SQL STATEMENT:" << endl;
  cout << "  CREATE TYPE" << endl;
  cout << "TO CREATE STRUCTURED TYPES\n" << endl;
  cout << "  CREATE TYPE PERSON_T " << endl;
  cout << "   AS (name VARCHAR(40), birthyear, integer) \n"
       << "   MODE DB2SQL\n"
       << "   REF USING INTEGER\n" << endl;

  EXEC SQL create type person_t as (name varchar(40), birthyear integer)
             mode db2sql REF USING INTEGER;
  EMB_SQL_CHECK("create type person_t");
  cout << "Created structured type, person_t.\n" << endl;

  cout << "  CREATE TYPE EMP_T\n"
       << "    UNDER PERSON_T\n"
       << "    AS ( salary integer ) \n"
       << "    MODE DB2SQL\n" << endl;


  EXEC SQL create type emp_t under person_t
              as ( salary integer ) mode db2sql;
  EMB_SQL_CHECK("create type emp_t");
  cout << "Created structured type, emp_t.\n" << endl;

  cout << "  CREATE TYPE PROF_T\n"
       << "    UNDER EMP_T\n"
       << "    AS ( speciality varchar(20) )\n"
       << "    MODE DB2SQL\n" << endl;

  EXEC SQL create type prof_t under emp_t
             as ( speciality varchar(20) )
             mode db2sql;
  EMB_SQL_CHECK("Create type prof_t");
  cout << "Created structured type, prof_t.\n" << endl;

  cout << "  CREATE TYPE STUDENT_T\n"
       << "    UNDER PERSON_T \n"
       << "    AS (major varchar(20), archivm decimal(5,2))\n"
       << "    MODE DB2SQL\n" << endl;

  EXEC SQL create type student_t under person_t as
      ( major varchar(20), archivm decimal(5,2) ) mode db2sql;
  EMB_SQL_CHECK("create type student_t");
  cout << "Created structured type, student_t.\n" << endl;

  cout << "  CREATE TYPE DEPT_T\n"
       << "    AS ( name varchar(20), budget integer, mgr ref(emp_t) )\n"
       << "    MODE DB2SQL\n"
       << "    REF USING INTEGER\n" << endl;

  EXEC SQL Create type dept_t
            as ( name varchar(20), budget integer, mgr ref(emp_t) )
            mode db2sql REF USING INTEGER;
  EMB_SQL_CHECK("create type dept_t");
  cout << "Created structured type, dept_t.\n" << endl;

  cout << "  COMMIT\n" << endl;
  EXEC SQL commit;
  EMB_SQL_CHECK("commit");

  cout << "\n-----------------------------------------------" << endl;
  cout << "USE THE SQL STATEMENT:" << endl;
  cout << "  ALTER TYPE" << endl;
  cout << "TO MODIFY AN EXISTING TYPE\n" << endl;
  cout << "  ALTER TYPE EMP_T\n"
       << "    ADD ATTRIBUTE DEPT\n"
       << "    REF (dept_t)\n" << endl;

  strcpy(aStmt, "Alter type emp_t add attribute dept ref(dept_t)");
  if (rc = AlterStructType(aStmt)) return rc;

  EXEC SQL Commit;
  EMB_SQL_CHECK("commit");

  return rc;

} // end of CreateStructTypes



// Alter a Structured type
int structtype::AlterStructType(char *stmt)
{
  EXEC SQL BEGIN DECLARE SECTION;
    char altEmpType[120];
  EXEC SQL END DECLARE SECTION;

  strcpy(altEmpType, stmt);
  EXEC SQL PREPARE altstat FROM :altEmpType;
  EMB_SQL_CHECK("PREPARE ALTER statment");

  EXEC SQL EXECUTE altstat;
  EMB_SQL_CHECK("EXECUTE altstate");

  return 0;

} // end of AlterStructType


int structtype::CreateTypedTables( )
{
  int rc = 0;
  char stmt[120];

  // Creates the typed tables
  while (1) {
    cout << "--------------------------------------------------" << endl;
    cout << " CREATE TABLE PERSON\n"
         << "   OF PERSON_T (ref is oid user generated)\n" << endl;

    strcpy(stmt, "create table person of person_t");
    strcat(stmt, " (ref is oid user generated)");
    if(rc = ExecuteStmt (stmt)) break;
    cout << "Created table person of person_t.\n" << endl;

    cout << " CREATE TABLE EMP_L OF EMP_T\n"
         << "   UNDER PERSON\n"
         << "   INHERIT SELECT PRIVILEGES\n" << endl;
    strcpy(stmt, "create table emp_l of emp_t under person ");
    strcat(stmt, "inherit select privileges");
    if(rc = ExecuteStmt(stmt)) break;
    cout << "Created table emp_l of emp_t.\n" << endl;

    cout << " CREATE TABLE PROF OF PROF_T\n"
         << "   UNDER EMP_L\n"
         << "   INHERIT SELECT PRIVILEGES\n" << endl;
    strcpy(stmt, "create table prof of prof_t under emp_l inherit");
    strcat(stmt, " select privileges");
    if(rc = ExecuteStmt(stmt)) break;
    cout << "Created table prof of prof_t.\n" << endl;

    cout << " CREATE TABLE STUDENT OF STUDENT_T\n"
         << "   UNDER PERSON INHERIT SELECT PRIVILEGES\n" << endl;
    strcpy(stmt, "create table student of student_t ");
    strcat(stmt, "under person inherit select privileges");
    if(rc = ExecuteStmt(stmt)) break;
    cout << "Created table student of student_t.\n" << endl;

    cout << " CREATE TABLE DEPT_N OF DEPT_T\n"
         << "   (REF IS OID USER GENERATED, MGR WITH OPTIONS SCOPE EMP_L)\n"
         << endl;
    strcpy(stmt, "create table dept_n of dept_t ");
    strcat(stmt, "(ref is oid user generated, mgr with options scope emp_l)");
    if(rc = ExecuteStmt(stmt)) break;
    cout << "Created table dept_n of dept_t.\n" << endl;

    cout << " ALTER TABLE EMP_L\n"
         << "   ALTER COLUMN DEPT ADD SCOPE DEPT_N\n" << endl;
    strcpy(stmt, "alter table emp_l alter column dept add scope dept_n");
    if (rc = ExecuteStmt(stmt)) break;
    cout << "Alter table emp_l of emp_t.\n" << endl;
    break;
  }

  return rc;

} // end of CreateTypedTbls


// Populates the typed tables
int structtype::PopulateTbls()
{
  int rc = 0;

  while ( 1 )
  {

    cout << "-------------------------------------------" << endl;
    cout << "Populates the tables ...\n\n" << endl;

    cout << "USE THE SQL STATEMENT:" << endl;
    cout << " INSERT " << endl;
    cout << "TO INSERT TABLE DATA\n" << endl;

    if (rc = InsertPerson(10, "John", "1970")) break;
    if (rc = InsertPerson(20, "Paul", "1962")) break;

    if (rc = InsertEmp(30, "Pat", "1968", 60000, 10)) break;
    if (rc = InsertEmp(40, "Hitomi", "1980", 67000, 20)) break;
    if (rc = InsertEmp(90, "Lou")) break;
    if (rc = InsertEmp(50, "Sam", "1968", 63000, 40)) break;
    if (rc = InsertEmp(60, "Uta", "1977", 95000, 30)) break;

    if (rc = InsertStudent(100, "Franzis", "1975", "pol", 2.5)) break;
    if (rc = InsertStudent(110, "Herb", "1980", "math", 1.7)) break;

    if (rc = InsertProf(70, "Rich", "1941", 90000, "oec", 30)) break;
    if (rc = InsertProf(80, "Herb", "1972", 120000, "math", 30)) break;

    if (rc = InsertDept(10, "math", 300000, 80)) break;
    if (rc = InsertDept(20, "oec", 500000, 70)) break;
    if (rc = InsertDept(30, "headq", 5000000, 90)) break;
    if (rc = InsertDept(40, "itso", 1000000, 60)) break;
      break;

  }

  return rc;

} // end of PopulateTbls


//Insert a record into table 'Person'
int structtype::InsertPerson(int id, char *name, char *year)
{
  EXEC SQL BEGIN DECLARE SECTION;
    char stmtBuf[120];
  EXEC SQL END DECLARE SECTION;


  sprintf(stmtBuf,
    "Insert into person (oid, name, birthyear) "
    "values (Person_t(%i), \'%s\', %s)",
    id, name, year);

  cout << "INSERT INTO Person (oid, name, birthyear)" << endl;
  cout << " VALUES (Person_t(" << id << "), '" << name << "', "
       << year << ")\n" << endl;

  EXEC SQL PREPARE insertStmt from :stmtBuf;
  EMB_SQL_CHECK("Prepare insertStmt");

  EXEC SQL EXECUTE insertStmt;
  EMB_SQL_CHECK("Execute insert person statement");

  return 0;

} // end of InsertPerson

//Insert a record into table Emp
int structtype::InsertEmp(
                    int id,
                    char *name,
                    char *birthYear,
                    int salary,
                    int deptID
                    )
{
  EXEC SQL BEGIN DECLARE SECTION;
    char instEmpstmtHv[120];
  EXEC SQL END DECLARE SECTION;


  sprintf(instEmpstmtHv,
    "insert into emp_l (oid, name, birthyear, salary, dept) "
    " values(emp_t(%i), \'%s\', %s, %i, dept_t(%i))",
      id, name, birthYear, salary, deptID);

  cout << "INSERT INTO Emp (oid, name, birthyear, salary, dept)" << endl;
  cout << " VALUES (Emp_t(" << id << "), '" << name << "', '" << birthYear
       << "', " << salary << ", Dept_t(" << deptID << "))\n"
       << endl;

  EXEC SQL PREPARE insertStmt from :instEmpstmtHv;
  EMB_SQL_CHECK("Prepare insertStmt");

  EXEC SQL EXECUTE insertStmt;
  EMB_SQL_CHECK("Execute insert emp_l statement");

  return 0;

} // end of InsertEmp


//Insert a row into table Emp
int structtype::InsertEmp(int id, char *name)
{
  EXEC SQL BEGIN DECLARE SECTION;
    char instEmpStmtHv[120];
  EXEC SQL END DECLARE SECTION;


  sprintf(instEmpStmtHv,
    "insert into emp_l (oid, name) values(emp_t(%i), \'%s\')", id, name);


  cout << "INSERT INTO Emp (oid, name)" << endl;
  cout << " VALUES (Emp_t(" << id << "), '" << name << "')\n"
       << endl;

  EXEC SQL PREPARE insertStmt from :instEmpStmtHv;
  EMB_SQL_CHECK("Prepare insertStmt");

  EXEC SQL EXECUTE insertStmt;
  EMB_SQL_CHECK("Execute insert emp_l statement");

  return 0;

} // end of InsertEmp

//Insert a row into table Student
int structtype::InsertStudent(
                int     id,
                char    *name,
                char    *birthYear,
                char    *major,
                double  archivm
                )
{
  EXEC SQL BEGIN DECLARE SECTION;
    char instStudentHv[120];
  EXEC SQL END DECLARE SECTION;


  sprintf(instStudentHv,
    "insert into student (oid, name, birthyear, major, archivm) "
    "values (student_t(%i), \'%s\', %s, \'%s\', %f)",
      id, name, birthYear, major, archivm);

  cout << "INSERT INTO Student (oid, name, birthyear, major, archivm)\n";
  cout << " VALUES (Student_t(" << id << "), '" << name << "', '"
       << birthYear << "', '" << major << "', " << archivm << ")\n"
       << endl;

  EXEC SQL PREPARE instStudent from :instStudentHv;
  EMB_SQL_CHECK("Prepare instStudent");

  EXEC SQL EXECUTE instStudent;
  EMB_SQL_CHECK("Execute insert student statement");

  return 0;

} // end of InsertStudent


//Insert a record into Prof table
int structtype::InsertProf(
      int id,
      char *name,
      char *birthYear,
      int salary,
      char *speciality, int dept)
{

  EXEC SQL BEGIN DECLARE SECTION;
    char insertProf[200];
  EXEC SQL END DECLARE SECTION;

  sprintf(insertProf,
    "Insert into prof (oid, name, birthyear, salary, speciality, dept) "
    "values (Prof_t(%i), \'%s\', %s, %i, \'%s\', Dept_t(%i))",
      id, name, birthYear, salary, speciality, dept);


  cout << "INSERT INTO Prof (oid, name, birthyear, salary, speciality,"
       << " dept)\n" << " VALUES (Prof_t(" << id << "), '" << name
       << "', '" << birthYear << "', " << salary << ", '"
       << speciality << "', Dept_t(" << dept << "))\n" << endl;

  EXEC SQL PREPARE instProf from :insertProf;
  EMB_SQL_CHECK("Prepare instStudent");

  EXEC SQL EXECUTE instProf;
  EMB_SQL_CHECK("Execute insert prof statement");

  return 0;
} // end of InsertProf

//Insert a row into table Dept_n
int structtype::InsertDept(int id, char *name, int budget, int mgrId)
{

  EXEC SQL BEGIN DECLARE SECTION;
    char insertDept[150];
  EXEC SQL END DECLARE SECTION;


  sprintf(insertDept,
    "insert into dept_n (oid, name, budget, mgr) "
    "values (dept_t(%i), \'%s\', %i, emp_t(%i))",
    id, name, budget, mgrId);

  cout << "INSERT INTO Dept_n (oid, name, budget, mgr)\n"
       << " VALUES (Dept_t(" << id << "), '" << name
       << "', " << budget << ", Emp_t(" << mgrId << "))\n" << endl;

  EXEC SQL PREPARE instDept from :insertDept;
  EMB_SQL_CHECK("Prepare instStudent");

  EXEC SQL EXECUTE instDept;
  EMB_SQL_CHECK("Execute insert Dept statement");

  return 0;

} // end of InsertDept


//Executes a dynamic embedded sql statement
int structtype::ExecuteStmt(char *aStatement)
{
  EXEC SQL BEGIN DECLARE SECTION;
    char stmtStr[120];
  EXEC SQL END DECLARE SECTION;

  strcpy(stmtStr, aStatement);

  EXEC SQL PREPARE aStmt from :stmtStr;
  EMB_SQL_CHECK("Prepare aStmt");

  EXEC SQL EXECUTE aStmt;
  EMB_SQL_CHECK("Execute aStmt");

  return 0;

} // end of ExecuteCrtStmt



// Compares root table and subtable
int structtype::ComparePersonEmpContents()
{

  int rc = 0;
  EXEC SQL BEGIN DECLARE SECTION;
    char stmt[120];
    short oidHv;
    char  empNamHv[30];
    short birthYearHv;
    sqlint32 salaryHv;
    short deptHv;
    short hvindPE;
    short hvindPEYear;
    char tblperson[30];
  EXEC SQL END DECLARE SECTION;

  int sqlcode = 0;


  cout << "\n----------------------------------------------------" << endl;
  cout << "Compare Root and Sub tables' contents\n" << endl;
  cout << "NOTE:" << endl;
  cout << "The following is the content of the 'Person' table." << endl;
  cout << "Person is the root-table which contains not only contents\n"
       << " of its own table but also the contents of its sub-tables.\n"
       << endl;

  cout << "SELECT oid, name, birthyear FROM Person\n" << endl;
  cout << "  ID            NAME          BIRTHYEAR" << endl;
  cout << "-----------------------------------------" << endl;

//  EXEC SQL DECLARE personCur CURSOR FOR
//        select oid, name, birthyear from :tblperson;

  strcpy(stmt, "select oid, name, birthyear from person");

  EXEC SQL PREPARE q1 FROM :stmt;
  EXEC SQL DECLARE personCur CURSOR FOR q1;

  EMB_SQL_CHECK("DECLARE CURSOR");

  EXEC SQL OPEN personCur;

  EMB_SQL_CHECK("OPEN CURSOR");

  hvindPEYear = 0;
  while(sqlcode != 100)
  {
    EXEC SQL FETCH personCur INTO
        :oidHv, :empNamHv, :birthYearHv :hvindPEYear;

    if (SQLCODE == 100)
      sqlcode = SQLCODE;
    else
    {
      cout << "  " << setw(3) << oidHv << "           " << setw(8)
           << empNamHv;
      cout.setf(ios::left, ios::adjustfield);

      if (hvindPEYear != -1)
        cout << "       " << birthYearHv << endl;
      else
        cout << "       " << "-" << endl;

      cout.setf(ios::left, ios::adjustfield);
    }
  }


  cout << "\n" << endl;

  EXEC SQL CLOSE personCur;
  EMB_SQL_CHECK("CLOSE CURSOR") ;


  cout << "NOTE:" << endl;
  cout << "The following is the content of the 'Emp_l' table, \n"
       << "which is a sub-table.\n" << endl;
  cout << "SELECT oid, name, birthyear, salary, dept FROM Emp_l\n" << endl;
  cout << "  ID      NAME      BIRTHYEAR    SALARY     DEPT" << endl;
  cout << "--------------------------------------------------"
       << endl;

//  EXEC SQL DECLARE empCur CURSOR FOR
//    select oid, name, birthyear, salary, dept from emp_l;

  strcpy(stmt,  "select oid, name, birthyear, salary, dept from emp_l");

  EXEC SQL PREPARE q2 FROM :stmt;
  EXEC SQL DECLARE empCur CURSOR FOR q2;

  EMB_SQL_CHECK("DECLARE CURSOR");

  EXEC SQL OPEN empCur;

  EMB_SQL_CHECK("OPEN CURSOR");

  sqlcode = 0;
  hvindPE = 0;
  hvindPEYear = 0;
  while(sqlcode != 100)
  {
    EXEC SQL FETCH empCur INTO :oidHv, :empNamHv, :birthYearHv :hvindPEYear,
                :salaryHv :hvindPE, :deptHv :hvindPE;
    if (SQLCODE == 100)
      sqlcode = SQLCODE;
    else
    {
      cout << "  " << oidHv << "      " << setw(8) << empNamHv;

      if (hvindPE != -1)
        cout << "  " << birthYearHv;
      else
        cout << "  " << "-";

      if (hvindPE != -1)
        cout << "         " << setw(8) << salaryHv << "    " << deptHv << endl;
      else
        cout << "           " << setw(8) << " -"      << "     " << "-" << endl;

      cout.setf(ios::left, ios::adjustfield);
    }
  }

  cout << "\n" << endl;

  EXEC SQL CLOSE empCur;
  EMB_SQL_CHECK("CLOSE CURSOR") ;

  return 0;

} // end of ComparePersonEmpContents


// Update the records of table person where oid=id
int structtype::UptPersonBirth(int birthYear, int id)
{
  EXEC SQL BEGIN DECLARE SECTION;
    char uptPersonStmt[120];
  EXEC SQL END DECLARE SECTION;

  sprintf(uptPersonStmt, "UPDATE Person SET birthyear=%i "
      "WHERE oid=Emp_t(%i)", birthYear, id);

  cout << "UPDATE Person" << endl;
  cout << " SET birthyear=" << birthYear << endl;
  cout << " WHERE oid=Emp_t(" << id << ")\n" << endl;

  EXEC SQL EXECUTE IMMEDIATE :uptPersonStmt;
  EMB_SQL_CHECK("Update Table Person");

  return 0;

} // end of UptPersonBirth

// Demonstrate ONLY and OUTER
int structtype::ShowOnlyOuterEmp()
{
  EXEC SQL BEGIN DECLARE SECTION;
    char stmt2[120];
    short oidOutHv;
    char  empNamOutHv[30];
    short birthYearOutHv;
    sqlint32 salaryOutHv;
    short deptOutHv;
    short hvindOOE;
  EXEC SQL END DECLARE SECTION;

  int sqlcode = 0;


  cout << "\n-------------------------------------------" << endl;
  cout << "SHOW ONLY and OUTER\n" << endl;
  cout << "SELECT * FROM ONLY(Emp_l)\n" << endl;
  cout << "  ID       NAME    BIRTHYEAR   SALARY    DEPT" << endl;
  cout << "-----------------------------------------------" << endl;


//  EXEC SQL DECLARE onlyCur CURSOR FOR
//    select * from ONLY(emp_l);

  strcpy(stmt2, "select * from ONLY(emp_l)");
  EXEC SQL PREPARE q3 FROM :stmt2;
  EXEC SQL DECLARE onlyCur CURSOR FOR q3;

  EMB_SQL_CHECK("DECLARE CURSOR");

  EXEC SQL OPEN onlyCur;
  EMB_SQL_CHECK("OPEN CURSOR");

  hvindOOE = 0;
  while(sqlcode != 100)
  {
    EXEC SQL FETCH onlyCur INTO :oidOutHv, :empNamOutHv,
      :birthYearOutHv :hvindOOE, :salaryOutHv :hvindOOE,
      :deptOutHv :hvindOOE;

    if (SQLCODE == 100)
      sqlcode = SQLCODE;
    else
    {
      cout << "  " << oidOutHv << "       " << setw(8) << empNamOutHv;
      if (hvindOOE != -1)
        cout << birthYearOutHv << "        " << setw(8) << salaryOutHv
             << "   " << deptOutHv << endl;
      else
        cout << "-   " << "        " << setw(8) << "-" << "   " << "-"
             << endl;

      cout.setf(ios::left, ios::adjustfield);
    }

  }


  EXEC SQL CLOSE onlyCur;
  EMB_SQL_CHECK("CLOSE CURSOR") ;


  cout << "\n\nSELECT * FROM OUTER(Emp_l)\n" << endl;
  cout << "  ID     NAME     BIRTHYEAR   SALARY     DEPT" << endl;
  cout << "-----------------------------------------------" << endl;

//  EXEC SQL DECLARE outerCur CURSOR FOR
//    select * from OUTER(emp_l);
  strcpy(stmt2, "select * from OUTER(emp_l)");
  EXEC SQL PREPARE q4 FROM :stmt2;
  EXEC SQL DECLARE outerCur CURSOR FOR q4;

  EMB_SQL_CHECK("DECLARE CURSOR");

  EXEC SQL OPEN outerCur;
  EMB_SQL_CHECK("OPEN CURSOR");

  sqlcode = 0;
  hvindOOE = 0;
  while (sqlcode != 100)
  {
    EXEC SQL FETCH outerCur INTO :oidOutHv, :empNamOutHv, :birthYearOutHv :hvindOOE,
        :salaryOutHv :hvindOOE, :deptOutHv :hvindOOE;
    if (SQLCODE == 100)
      sqlcode = SQLCODE;
    else
    {
      cout << "  " << oidOutHv << "     " << setw(6)
           << empNamOutHv << "   ";
      if (hvindOOE != -1)
        cout << birthYearOutHv << "       " << setw(8) << salaryOutHv
             << "    " << deptOutHv << endl;
      else
        cout << "-    " << "      " << setw(8) << "-" << "    "
             << "-" << endl;

      cout.setf(ios::left, ios::adjustfield);
    }

  }

  cout << "\n" << endl;

  EXEC SQL CLOSE outerCur;
  EMB_SQL_CHECK("CLOSE CURSOR") ;

  return 0;

} // end of ShowOnlyOuterEmp


// Show name and dept name for all employees
int structtype::ShowEmpsDept()
{
  EXEC SQL BEGIN DECLARE SECTION;
    char  empNameDeptHv[30];
    char  slStmtDeptHv[220];
    char  empsDeptHv[30];
    short hvindED;
  EXEC SQL END DECLARE SECTION;

  int sqlcode = 0;


  strcpy(slStmtDeptHv, "select E.name, E.dept->name from emp_l E");

  cout << "\n---------------------------------------------" << endl;
  cout << "USE THE SQL STATEMENT:" << endl;
  cout << " SELECT" << endl;
  cout << "DEPT NAME FOR ALL EMPLOYEES\n" << endl;
  cout << "SELECT E.name, E.dept->name FROM Emp E\n" << endl;
  cout << "  Name           Dept" << endl;
  cout << "-----------------------" << endl;

  // Prepare the query statement
  EXEC SQL PREPARE selempDeptStmt From :slStmtDeptHv;
  EMB_SQL_CHECK("Prepare select statement");

  // Declare a cursor for the query
  EXEC SQL DECLARE empDeptCur CURSOR FOR selempDeptStmt;
  EMB_SQL_CHECK("DECLARE CURSOR");

  EXEC SQL OPEN empDeptCur;
  EMB_SQL_CHECK("OPEN CURSOR");

  hvindED = 0;
  while(sqlcode != 100)
  {
    EXEC SQL FETCH empDeptCur INTO :empNameDeptHv, :empsDeptHv :hvindED;

    if (SQLCODE == 100)
      sqlcode = SQLCODE;
    else
    {
      cout << "  "  << setw(8) << empNameDeptHv << "       ";

      if (hvindED != -1)
        cout << empsDeptHv << endl;
      else
        cout << "-" << endl;

      cout.setf(ios::left, ios::adjustfield);
    }
  }

  cout << "\n" << endl;

  EXEC SQL CLOSE empDeptCur;
  EMB_SQL_CHECK("CLOSE CURSOR") ;

  strcpy(slStmtDeptHv,
    "select E.name, "
    "(select D.name from dept_n D where D.oid=E.dept) from emp_l E");

  cout << "SELECT E.name, SELECT D.name FROM dept_n D WHERE D.oid=E.dept)\n"
       << " FROM Emp E\n" << endl;
  cout << "  Name           Dept" << endl;
  cout << "-----------------------" << endl;

  // Prepare the query statement
  EXEC SQL PREPARE selEmpDeptStmt2 From :slStmtDeptHv;
  EMB_SQL_CHECK("Prepare select statement");

  // Declare a cursor for the query
  EXEC SQL DECLARE empDeptCur2 CURSOR FOR selEmpDeptStmt2;
  EMB_SQL_CHECK("DECLARE CURSOR");

  EXEC SQL OPEN empDeptCur2;
  EMB_SQL_CHECK("OPEN CURSOR");

  sqlcode = 0;
  hvindED = 0;
  while(sqlcode != 100)
  {
    EXEC SQL FETCH empDeptCur2 INTO :empNameDeptHv, :empsDeptHv :hvindED;

    if (SQLCODE == 100)
      sqlcode = SQLCODE;
    else
    {
      cout << "  "  << setw(8) << empNameDeptHv << "       ";

      if (hvindED != -1)
        cout << empsDeptHv << endl;
      else
        cout << "-" << endl;
      cout.setf(ios::left, ios::adjustfield);
    }
  }

  cout << "\n" << endl;

  EXEC SQL CLOSE empDeptCur2;
  EMB_SQL_CHECK("CLOSE CURSOR") ;

  return 0;

} // endl of ShowEmpsDept


// Select Employees whose manager's manager is the input
int structtype::ShowMgrEmps(char *mgr)
{
  EXEC SQL BEGIN DECLARE SECTION;
    char  mgrHv[30];
    char  empNameHv[30];
    char  slStmtHv[220];
    short oidMgrHv;
  EXEC SQL END DECLARE SECTION;

  int sqlcode = 0;

  strcpy(mgrHv, mgr);
  strcpy(slStmtHv, "Select e.name from emp_l e  ");
  strcat(slStmtHv, "where e.dept->mgr->dept->mgr->name = ?");
  strcat(slStmtHv, "ORDER BY e.name");

  cout << "\n--------------------------------------------------------"
       << endl;
  cout << "Select employees whose manager's manager is " << mgr
       << "\n" << endl;
  cout << "USE THE SQL STATEMENT:" << endl;
  cout << "SELECT e.name from emp_l e  \n"
       << " WHERE e.dept->mgr->dept->mgr->name = '" << mgr
       << "' ORDER BY e.name"
       << "\n" << endl;
  cout << "  Name           Manager" << endl;
  cout << "--------------------------" << endl;


  // Prepare the query statement
  EXEC SQL PREPARE selStmt From :slStmtHv;
  EMB_SQL_CHECK("Prepare select statement");

  // Declare a cursor for the query
  EXEC SQL DECLARE mgrC1 CURSOR FOR selStmt;
  EMB_SQL_CHECK("DECLARE CURSOR");

  EXEC SQL OPEN mgrC1 USING :mgrHv;
  EMB_SQL_CHECK("OPEN CURSOR");


  while(sqlcode != 100)
  {
    EXEC SQL FETCH mgrC1 INTO :empNameHv;

    if (SQLCODE == 100)
      sqlcode = SQLCODE;
    else
    {
      cout << "  "  << setw(8) << empNameHv << "       "
           << setw(8) << mgrHv << endl;

      cout.setf(ios::left, ios::adjustfield);
    }
  }

  cout << "\n" << endl;

  EXEC SQL CLOSE mgrC1;
  EMB_SQL_CHECK("CLOSE CURSOR") ;


  cout << "USE THE SQL STATEMENT:" << endl;
  cout << "SELECT e3.name FROM emp_l e1, dept_n d1, emp_l e2, dept_n d2, emp_l e3\n"
       << " WHERE e1.name = '" << mgr << "' and e1.oid  = d1.mgr \n"
       << "       and d1.oid  = e2.dept and e2.oid  = d2.mgr \n"
       << "       and d2.oid  = e3.dept\n"<< endl;
  cout << "  Name            Manager" << endl;
  cout << "---------------------------" << endl;

  strcpy(slStmtHv,
    "select e3.name from emp_l e1, dept_n d1, emp_l e2, dept_n d2, emp_l e3 ");
  strcat(slStmtHv,
    "where e1.name = ? and e1.oid  = d1.mgr and d1.oid  = e2.dept ");
  strcat(slStmtHv, " and e2.oid  = d2.mgr and d2.oid  = e3.dept");


  EXEC SQL PREPARE selStmt2 From :slStmtHv;
  EMB_SQL_CHECK("Prepare select statement");

  EXEC SQL DECLARE mgrC2 CURSOR FOR selStmt2;
  EMB_SQL_CHECK("DECLARE CURSOR");

  EXEC SQL OPEN mgrC2 using :mgrHv;

  sqlcode = 0;
  while(sqlcode != 100)
  {
    EXEC SQL FETCH mgrC2 INTO :empNameHv;

    if (SQLCODE == 100)
      sqlcode = SQLCODE;
    else
    {
      cout << "  " << setw(8) << empNameHv << "        "
           << setw(8) << mgrHv << endl;
      cout.setf(ios::left, ios::adjustfield);
    }

  }


  EXEC SQL CLOSE mgrC2;
  EMB_SQL_CHECK("CLOSE CURSOR");

  return 0;

} // end of ShowMgrEmps


int structtype::DropStructTables()
{
  int rc = 0;

  cout << "\n\nDROP the hierarchy of structured tables ...\n" << endl;
  cout << "\n------------------------" << endl;
  cout << "USE THE SQL STATEMENT:" << endl;
  cout << " DROP TABLE\n"
       << "TO DROP A TYPED TABLE\n" << endl;

  cout << " DROP TABLE prof\n" << endl;
  if (rc = DropTypeOrTable("prof", DROP_TABLE)) return rc;

  cout << " DROP TABLE student\n" << endl;
  if (rc = DropTypeOrTable("student", DROP_TABLE)) return rc;

  cout << " DROP TABLE dept_n\n" << endl;
  if (rc = DropTypeOrTable("dept_n", DROP_TABLE)) return rc;

  cout << " DROP TABLE emp_l\n" << endl;
  if (rc = DropTypeOrTable("emp_l", DROP_TABLE)) return rc;

  cout << " DROP TABLE person\n" << endl;
  if (rc = DropTypeOrTable("person", DROP_TABLE)) return rc;

  return rc;

} // end of DropStructTbls


int structtype::DropStructTypes( )
{
  int rc = 0;
  char stmt3[120];

  cout << "\nDROP the hierarchy of structured types ..." << endl;
  cout << "\n---------------------------------------" << endl;
  cout << "USE THE SQL STATEMENT:" << endl;
  cout << " DROP TYPE\n"
       << "TO DROP A STRUCTURED TYPE\n" << endl;

  cout << " DROP TYPE prof_t\n" << endl;
  if (rc = DropTypeOrTable("prof_t", DROP_TYPE)) return rc;

  cout << " DROP TYPE student_t\n" << endl;
  if (rc = DropTypeOrTable("student_t", DROP_TYPE)) return rc;


  cout << "\n---------------------------------------------" << endl;
  cout << "USE THE SQL STATEMENT:" << endl;
  cout << " ALTER TYPE" << endl;
  cout << "TO MODIFY AN EXISTING STRUCTURED TYPE\n" << endl;

  // Alter type emp_t to drop attribute dept
  cout << " ALTER TYPE emp_t\n"
       << "  DROP ATTRIBUTE dept\n" << endl;

  cout << "NOTE:\n"
       << " The attribute dept associated with the structured\n"
       << " type emp_t must be dropped before the structure type\n"
       << " dept can be dropped.\n" << endl;

//  EXEC SQL alter type emp_t drop attribute dept;
  strcpy(stmt3, " alter type emp_t drop attribute dept");
  rc = ExecuteStmt(stmt3);
  if (rc != 0)
  {
    return rc;
  }

  EMB_SQL_CHECK("Alter type emp_t");

  cout << " DROP TYPE dept_t\n" << endl;
  if (rc = DropTypeOrTable("dept_t", DROP_TYPE)) return rc;

  cout << " DROP TYPE emp_t\n" << endl;
  if (rc = DropTypeOrTable("emp_t", DROP_TYPE)) return rc;

  cout << " DROP TYPE person_t\n" << endl;
  if (rc = DropTypeOrTable("person_t", DROP_TYPE)) return rc;

  return rc;

} // DropStructTypes


int structtype::DropTypeOrTable(char *objName, int objType)
{
  EXEC SQL BEGIN DECLARE SECTION;
    char dropState[120];
  EXEC SQL END DECLARE SECTION;

  int rc = 0;
  char errMsg[120];

  if (objType == DROP_TABLE)
  {
    sprintf(dropState, "drop table %s", objName);
    sprintf(errMsg, "Execute DROP TABLE %s statement\n", objName);
  }
  else
  {
    sprintf(dropState, "drop type %s", objName);
    sprintf(errMsg, "Execute DROP TYPE %s statement\n", objName);
  }


  EXEC SQL EXECUTE IMMEDIATE :dropState;
  EMB_SQL_CHECK(errMsg);

  return rc;

} // end of DropTypeOrTable