/* ================================================================ */
/* The CITY Benchmark Table Creation Program.			    */
/* This Program Creates DB100, DB200, DB300, DBUPD, DBINS.	    */
/* Last update: 27/7/93.					    */
/* Copyright 1993 Dr. Wagdy Youssef. All Rights Reserved.           */
/* ================================================================ */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define BEEP '\a'
#define MAXPATH 64
#define MAXLINE 80
#define DSECONDS 1
#define NLETTERS 10

/* ================================ */
/* Declare TPS record Structure TAG */
/* ================================ */

struct tps_rec_layout
      { /* Structure begining */
       char  dbtype[15];		/* database name.    */
       long  dbsize;			/* Database size.    */
       int   nloops;			/* Number of loops.  */
       int   looptime;			/* Loop time in seconds. */
       int   tottime;			/* Total time in seconds. */
       long  tot_trans;			/* Tot. number of transactions. */
       long  avr_trans;			/* Avr. transactions per loop. */
       double trn_per_sec;		/* Number of transactions/sec. */
       double it_resp_time;		/* Iteration response time. */
       time_t time_date;		/* Time and date of test. */
      }; /* Stucture end */

/* ============================ */
/* Declare TPS Record Structure */
/* ============================ */

struct tps_rec_layout tps_io_rec;

/* ======================= */
/* Declare print procedure */
/* ======================= */

    prn_rec1();

/* ==================================================== */
/* This part creates five Tables for The CITY Benchmark */
/* DB100, DB200, DB300 DBINS and DBUPD then load them.	*/
/* ==================================================== */

EXEC SQL BEGIN DECLARE SECTION;

/* ================================ */
/* The PassWord Declaration Section */
/* ================================ */

     VARCHAR uid[20];
     VARCHAR pwd[20];

/* ============================================== */
/* The Databases intermediate declaration section */
/* ============================================== */

     char    dbfc1 [8];
     int     dbfi;
     char    dbfc2 [30];
     long    dbfl;
     float   dbfr;
     double  dbfd;
     VARCHAR dbfv [40];

     unsigned int  key_value;

/* ========================================== */
/* The program variables declaration section. */
/* ========================================== */

     long   r_1   = 0; /* Unique No. of Rows Counter. */
     long   r_10  = 0; /* No. of Rows Counter repeated every 10 rows. */
     long   r_100 = 0; /* No. of Rows Counter repeated every 100 rows. */

     int    vi = 50;	 /* Integer value */
     long   vl = 50;	 /* Long value */
     float  vf = 50;	 /* Float value */
     float  vr = 50;	 /* Float value */
     double vd = 50;	 /* Double value */


      /* Character fields Car1field1, Char2field1 and Varfield1	*/

  static char Char1field1 [8]  = {"0000001"};
  static char Char2field1 [30] = {"ABABA ABABA ABABA ABABA ABABA"};
  static char Varfield1   [40] = {"ABABA ABABA ABABA ABABA ABABA ABA AAAAA"};

EXEC SQL END DECLARE SECTION;

/* ====================================== */
/* Include SQLCA command (SQL Comm Area). */
/* ====================================== */

EXEC SQL INCLUDE sqlca.h;


/* =========================================================== */
/* External variables for the random number generation program */
/* =========================================================== */
extern int srand1(), rand2(); /* extern is optional */


/* ======================= */
/* The main program start. */
/* ======================= */

main()
{   /* Program START */

     FILE *tps_fp;
     long randp();

     long x, y, z;

     static char path_name_1[MAXPATH] ="TSTCITY.TXT";

      /* Random number generation variables */
     long seed, rt_value, n_rows, r_limit10;
     int r_limit = 30000; /* randp maximum value */
     unsigned long  ROWS; /* DATABASE SIZE */

     unsigned long  Rows_Start, /* Number of rows start value */
		    Rows_End,	/* Number of rows end value */
		    Rows_Step;	/* Number of rows step value */

     int SECONDS;

     int i1 = 0, /* loop1 index */
         i2 = 0, /* loop2 index */
	 i3 = 0; /* loop3 index */

     int     i,       /* Main loop index		*/
             j = 7,   /* End of 8 Char field pointer    */
             k = 29,  /* End of 30 Char field pointer   */
             l = 0,   /* Start of Var_fields pointer    */
             m = 38;  /* End of Var_fields pointer      */

     unsigned int     i_loops = 0;  /* Index of loops for time measues. */
     unsigned long    rows_loop = 0;  /* Database load loops Index */
     unsigned long    start   = 0, /* TPS Start time. */
		      end     = 0, /* TPS End time. */
		      g_time1 = 0, /* Used to get start value from time. */
		      g_time2 = 0; /* Used to get end value from time. */

     unsigned long   trans_count     = 0, /* Loop trans_counter.	*/
		     tot_trans_count = 0, /* Total of loop trans_counters. */
		     avr_trans_count = 0; /* Average of loop trans_counters. */

     double resp_time,	     /* Final transactions response time. */
            resp_time_t,     /* Total transactions response time. */
            resp_time_1,     /* One iteration response time. */
	    resp_per_step,   /* Response time per step. */
	    trans_per_sec;   /* Transactions/sec. */

     time_t resp_time_start, /* Response time Start. */
	    resp_time_stop;  /* Response time End. */

     unsigned long resp_count;

     static    char    db_type	[15] = {"ORACLE.       "};

     long    qs=0;
     long    qu1=0;
     long    qu2=0;
     long    qf=0;
     long    in_rec=0;

     double  tr_per_second= 0; /* Average number of transactions/sec. */

  static char error_message[71] =
{"                                                                      "};

  static char	 line[71] =
{"######################################################################"};

  static char conn_err[71] =
{"An error occurred during connection to the DBMS.                      "};

  static char tabl100_drop_err[71] =
{"An error occurred during Table DB100 DROP.                            "};
  static char indx100_err[71] =
{"An error occurred during Index DB100_IX creation.                     "};
  static char tabl100_cr_err[71] =
{"An error occurred during Table DB100 creation.                        "};

  static char tabl200_drop_err[71] =
{"An error occurred during Table DB200 DROP.                            "};
  static char indx200_err[71] =
{"An error occurred during Index DB200_IX creation.                     "};
  static char tabl200_cr_err[71] =
{"An error occurred during Table DB200 creation.                        "};

  static char tabl300_drop_err[71] =
{"An error occurred during Table DB300 DROP.                            "};
  static char indx300_err[71] =
{"An error occurred during Index DB300_IX creation.                     "};
  static char tabl300_cr_err[71] =
{"An error occurred during Table DB300 creation.                        "};

  static char tablins_drop_err[71] =
{"An error occurred during Table DBINS DROP.                            "};
  static char indxins_err[71] =
{"An error occurred during Index DBINS_IX creation.                     "};
  static char tablins_cr_err[71] =
{"An error occurred during Table DBINS creation.                        "};

  static char tablupd_drop_err[71] =
{"An error occurred during Table DBUPD DROP.                            "};
  static char indxupd_err[71] =
{"An error occurred during Index DBUPD_IX creation.                     "};
  static char tablupd_cr_err[71] =
{"An error occurred during Table DBUPD creation.                        "};


/* ====================================== */
/* log into the DBMS userID and password. */
/* ====================================== */

    strcpy(uid.arr,"ops$za328");
    uid.len = strlen(uid.arr);
    strcpy(pwd.arr,"wagdy");
    pwd.len = strlen(pwd.arr);
		 

/* ========================================================== */
/* log into the DBMS every time the program start a new loop. */
/* ========================================================== */

    strcpy(error_message,conn_err);
    EXEC SQL WHENEVER SQLERROR GOTO SQL_error_routine;
    EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

    printf("* ======================================= *\n");
    printf("* Connected to The System user: %s *\n",uid.arr);
    printf("* ======================================= *\n\n");

/* ===================================================================== */
/* Drop Tables Section. This section ends with commit drop tables.       */
/* ===================================================================== */

/* ========================= */
/* Drop Table DB100 Section. */
/* ========================= */

   strcpy(error_message,tabl100_drop_err);
   EXEC SQL WHENEVER SQLERROR GOTO Drop_200;
   EXEC SQL DROP TABLE DB100;
   printf("* ============================= *\n");
   printf("* Table DB100 has been dropped. *\n");
   printf("* ============================= *\n");

/* ========================= */
/* Drop Table DB200 Section. */
/* ========================= */

Drop_200:
   strcpy(error_message,tabl200_drop_err);
   EXEC SQL WHENEVER SQLERROR GOTO Drop_300;
   EXEC SQL DROP TABLE DB200;
   printf("* Table DB200 has been dropped. *\n");
   printf("* ============================= *\n");

/* ========================= */
/* Drop Table DB300 Section. */
/* ========================= */

Drop_300:
   strcpy(error_message,tabl300_drop_err);
   EXEC SQL WHENEVER SQLERROR GOTO Drop_INS;
   EXEC SQL DROP TABLE DB300;
   printf("* Table DB300 has been dropped. *\n");
   printf("* ============================= *\n");

/* ========================= */
/* Drop Table DBINS Section. */
/* ========================= */

Drop_INS:
   strcpy(error_message,tablins_drop_err);
   EXEC SQL WHENEVER SQLERROR GOTO Drop_UPD;
   EXEC SQL DROP TABLE DBINS;
   printf("* Table DBINS has been dropped. *\n");
   printf("* ============================= *\n");

/* ========================= */
/* Drop Table DBUPD Section. */
/* ========================= */

Drop_UPD:
   strcpy(error_message,tablupd_drop_err);
   EXEC SQL WHENEVER SQLERROR GOTO Comm_Drop;
   EXEC SQL DROP TABLE DBUPD;
   printf("* Table DBUPD has been dropped. *\n");
   printf("* ============================= *\n\n");

/* =================== */
/* Commit DROP section */
/* =================== */

Comm_Drop:
    EXEC SQL COMMIT WORK;
    printf("* ============================================= *\n");
    printf("* DROP tables have Been Committed Successfully. *\n");
    printf("* ============================================= *\n");


/* ===================================================================== */
/* Create Tables Section. This section ends with commit create tables.   */
/* ===================================================================== */

/* ============================== */
/* Create Table DB100 Section.    */
/* ============================== */

   EXEC SQL WHENEVER SQLERROR GOTO SQL_error_routine;

    strcpy(error_message,tabl100_cr_err);
    EXEC SQL CREATE TABLE DB100
	    (db1fc1   char(8),		  /* No-key field. */
	     db1fi1   number(8) not null, /* Unique Key.   */
	     db1fc2   char(30), 	  /* No-key field. */
	     db1fl1   number(4),	  /* No-key field. */
	     db1fr1   number(4,2),	  /* No-key field. */
	     db1fd1   number(6,3),	  /* No-key field. */
	     db1fv1   char(40));	  /* No-key field. */


    printf("* ============================= *\n");
    printf("* Table DB100 has been created. *\n");
    printf("* ============================= *\n\n");

/* ================================ */
/* Create Index DB1FC1_IX. Section. */
/* ================================ */

   strcpy(error_message,indx100_err);

   EXEC SQL CREATE UNIQUE INDEX DB1FI1_IX ON DB100(DB1FI1);
   printf("* =========================================== *\n");
   printf("* UNIQUE INDEX DB1FI1_IX has been Created.    *\n");
   printf("* An Index on DB100 table field db1fi1.       *\n");
   printf("* =========================================== *\n");


/* ============================== */
/* Create Table DB200 Section.    */
/* ============================== */

    strcpy(error_message,tabl200_cr_err);
    EXEC SQL CREATE TABLE DB200
	    (db2fc1   char(8),		  /* No-key field.	      */
	     db2fi1   number(8) not null, /* Unique Key.	      */
	     db2fc2   char(30), 	  /* No-key field.	      */
	     db2fl1   number(4),	  /* No-key field.	      */
	     db2fr1   number(4,2),	  /* No-key field.	      */
	     db2fd1   number(6,3),	  /* No-key field.	      */
	     db2fv1   char(40), 	  /* No-key field.	      */
	     db2fc3   char(8),		  /* No-key field.	      */
	     db2fi2   number(8) not null, /* Secondary Key 10  times. */
	     db2fc4   char(30), 	  /* No-key field.	      */
	     db2fl2   number(4),	  /* No-key field.	      */
	     db2fr2   number(4,2),	  /* No-key field.	      */
	     db2fd2   number(6,3),	  /* No-key field.	      */
	     db2fv2   char(40));	  /* No-key field.	      */


    printf("* ============================= *\n");
    printf("* Table DB200 has been created. *\n");
    printf("* ============================= *\n\n");

/* ================================= */
/* Create Indexes for DB200 Section. */
/* ================================= */

   strcpy(error_message,indx200_err);

   EXEC SQL CREATE UNIQUE INDEX DB2FI1_IX ON DB200(DB2FI1);
   printf("* =========================================== *\n");
   printf("* UNIQUE INDEX DB2FI1_IX has been Created.    *\n");
   printf("* An Index on DB200 table field db2fi1.       *\n");
   printf("* =========================================== *\n");

   /* Secondary Key 10	times */
   EXEC SQL CREATE INDEX DB2FI2_IX ON DB200(DB2FI2);
   printf("* SECONDARY INDEX DB2FI2_IX has been Created. *\n");
   printf("* An Index on DB200 table field db2fi2.       *\n");
   printf("* =========================================== *\n");


/* ============================== */
/* Create Table DB300 Section.    */
/* ============================== */

    strcpy(error_message,tabl300_cr_err);
    EXEC SQL CREATE TABLE DB300
	    (db3fc1   char(8),		  /* No-key field.		*/
	     db3fi1   number(8) not null, /* Unique Key.		*/
	     db3fc2   char(30), 	  /* No-key field.		*/
	     db3fl1   number(4),	  /* No-key field.		*/
	     db3fr1   number(4,2),	  /* No-key field.		*/
	     db3fd1   number(6,3),	  /* No-key field.		*/
	     db3fv1   char(40), 	  /* No-key field.		*/
	     db3fc3   char(8),		  /* No-key field.		*/
	     db3fi2   number(8) not null, /* Secondary Key 10  times.	*/
	     db3fc4   char(30), 	  /* No-key field.		*/
	     db3fl2   number(4),	  /* No-key field.		*/
	     db3fr2   number(4,2),	  /* No-key field.		*/
	     db3fd2   number(6,3),	  /* No-key field.		*/
	     db3fv2   char(40), 	  /* No-key field.		*/
	     db3fc5   char(8),		  /* No-key field.		*/
	     db3fi3   number(8) not null, /* Secondary Key 100	times.	*/
	     db3fc6   char(30), 	  /* No-key field.		*/
	     db3fl3   number(4),	  /* No-key field.		*/
	     db3fr3   number(4,2),	  /* No-key field.		*/
	     db3fd3   number(6,3),	  /* No-key field.		*/
	     db3fv3   char(40));	  /* No-key field.		*/


    printf("* ============================= *\n");
    printf("* Table DB300 has been created. *\n");
    printf("* ============================= *\n\n");


/* ================================= */
/* Create Indexes for DB300 Section. */
/* ================================= */

   strcpy(error_message,indx300_err);

   EXEC SQL CREATE UNIQUE INDEX DB3FI1_IX ON DB300(DB3FI1);
   printf("* =========================================== *\n");
   printf("* UNIQUE INDEX DB3FI1_IX has been Created.    *\n");
   printf("* An Index on DB300 table field db3fi1.       *\n");
   printf("* =========================================== *\n");

   /* Secondary Key 10 times	*/
   EXEC SQL CREATE INDEX DB3FI2_IX ON DB300(DB3FI2);
   printf("* SECONDARY INDEX DB3FI2_IX has been Created. *\n");
   printf("* An Index on DB300 table field db3fi2.       *\n");
   printf("* =========================================== *\n");

   /* Secondary Key 100 times	 */
   EXEC SQL CREATE INDEX DB3FI3_IX ON DB300(DB3FI3);
   printf("* SECONDARY INDEX DB3FI3_IX has been Created. *\n");
   printf("* An Index on DB300 table field db3fi3.       *\n");
   printf("* =========================================== *\n");


/* ============================== */
/* Create Table DBINS Section.    */
/* ============================== */

    strcpy(error_message,tablins_cr_err);
    EXEC SQL CREATE TABLE DBINS
	    (dbifc1   char(8),			  /* No-key field. */
	     dbifi1   number(8) not null,	  /* Secondary Key.*/
	     dbifc2   char(30), 		  /* No-key field. */
	     dbifl1   number(4),		  /* No-key field. */
	     dbifr1   number(4,2),		  /* No-key field. */
	     dbifd1   number(6,3),		  /* No-key field. */
	     dbifv1   char(40), 		  /* No-key field. */
	     dbifc3   char(8),			  /* No-key field. */
	     dbifi2   number(8) not null,	  /* No-key field. */
	     dbifc4   char(30), 		  /* No-key field. */
	     dbifl2   number(4),		  /* No-key field. */
	     dbifr2   number(4,2),		  /* No-key field. */
	     dbifd2   number(6,3),		  /* No-key field. */
	     dbifv2   char(40));		  /* No-key field. */

    printf("* ============================= *\n");
    printf("* Table DBINS has been created. *\n");
    printf("* ============================= *\n\n");

/* ================================= */
/* Create Indexes for DBINS Section. */
/* ================================= */

   strcpy(error_message,indxins_err);
   /* Secondary Key n times Depending on no. of transactions. */
   EXEC SQL CREATE INDEX DBIFI1_IX ON DBINS(DBIFI1);
   printf("* =========================================== *\n");
   printf("* SECONDARY INDEX DBIFI1_IX has been Created. *\n");
   printf("* An Index on DBINS table field dbifi1.       *\n");
   printf("* =========================================== *\n");


/* ============================== */
/* Create Table DBUPD Section.    */
/* ============================== */

    strcpy(error_message,tablupd_cr_err);
    EXEC SQL CREATE TABLE DBUPD
	    (dbufc1   char(8),			  /* No-key field. */
	     dbufi1   number(8) not null,	  /* Unique Key.   */
	     dbufc2   char(30), 		  /* No-key field. */
	     dbufl1   number(4),		  /* No-key field. */
	     dbufr1   number(4,2),		  /* No-key field. */
	     dbufd1   number(6,3),		  /* No-key field. */
	     dbufv1   char(40), 		  /* No-key field. */
	     dbufc3   char(8),			  /* No-key field. */
	     dbufi2   number(8) not null,	  /* Secondary Key.*/
	     dbufc4   char(30), 		  /* No-key field. */
	     dbufl2   number(4),		  /* No-key field. */
	     dbufr2   number(4,2),		  /* No-key field. */
	     dbufd2   number(6,3),		  /* No-key field. */
	     dbufv2   char(40));		  /* No-key field. */

    printf("* ============================= *\n");
    printf("* Table DBUPD has been created. *\n");
    printf("* ============================= *\n\n");

/* ================================= */
/* Create Indexes for DBUPD Section. */
/* ================================= */

   strcpy(error_message,indxupd_err);

   EXEC SQL CREATE UNIQUE INDEX DBUFI1_IX ON DBUPD(DBUFI1);
   printf("* =========================================== *\n");
   printf("* UNIQUE INDEX DBUFI1_IX has been Created.    *\n");
   printf("* An Index on DBUPD table field db2fi1.       *\n");
   printf("* =========================================== *\n");


/* ============================== */
/* Commit Tables Creation Section */
/* ============================== */

    EXEC SQL COMMIT WORK;
    printf("* =============================================== *\n");
    printf("* CREATE Tables Have Been Committed Successfully. *\n");
    printf("* =============================================== *\n");


/* ==================================================================== */
/* Normal program termination section.					*/
/* Log out and terminate processing.					*/
/* ==================================================================== */

    EXEC SQL WHENEVER SQLERROR CONTINUE; /* don't trap errors. */
    EXEC SQL COMMIT WORK RELEASE;   /* log off database.  */
    printf("\n\n* ==================================== *\n");
    printf("* The program has terminated normally. *\n");
    printf("* ==================================== *\n");

exit(0);

/* *********************************************************************** */
/* The error handling traps and routines.				   */
/* *********************************************************************** */

SQL_error_routine:
	 putchar(BEEP);	/* Beep */
	 printf("* %70s *\n",line);
	 printf("* Database Size    : %lu\n",ROWS);
	 printf("* Last Key Value is: %d\n",key_value);
	 printf("* %70s *\n",line);
	 printf("* %70s *\n", error_message);
	 printf("* %70s *\n", sqlca.sqlerrm.sqlerrmc);
         printf("* %70s *\n",line);
	 putchar(BEEP);	/* Beep */
	 EXEC SQL WHENEVER SQLERROR CONTINUE;
         EXEC SQL ROLLBACK WORK RELEASE;
	 exit(1);

}   /* Program END */

/* ========================= */
/* Line printing subroutine. */
/* ========================= */

prn_rec1(qp) long qp;
       { /* prn_rec1() start */
	 printf ("Transaction Number: %8d\n", qp);
	 printf ("Integer   Field : %8d \n", dbfi );
	 printf ("Character Field1: %8s \n", dbfc1);
	 printf ("Character Field2: %30s \n", dbfc2);
	 printf ("Long      Field : %8d \n", dbfl);
	 printf ("Real      Field : %f \n", dbfr);
	 printf ("Double    Field : %f \n", dbfd);
	 printf ("VarChar   Field : %40s \n", dbfv.arr);
      } /* prn_rec1() end */

/* ************************************************************** */
/* This procedure generates random numbers within a given range.  */
/* ************************************************************** */

/* =============================== */
/* Generate pseudo random numbers. */
/* =============================== */

long randp ( x, y, z,limit )
     long x, y, z,limit;
      { /* random function start */
      /* This random number generator is based upon NPL Report DITC 6/82 by
         B.A.Wichmann and I.D.Hill. x,y,z are global variables to be given
         initial random integer values which should be less than 30000 */

       float w;
       long lw;
       long random;

       x = 171*(x % 177) - 2*(x / 177);
       if (x < 0) x = x+30269;

       y = 172*(y % 176) - 35*(y / 176);
       if (y < 0) y = y+30307;

       z =170*(z % 178) - 63*(z / 178);
       if (z < 0) z = z+30323;

       w = (float) x/30269 + (float) y/30307+ (float) z/30323;
       lw = w;
       random = (w - lw) * limit /* max value */ ;

       return (random);
      } /* randp function end */

/* ************************************************************** */
/* This procedure generates random numbers within a given range.  */
/* ************************************************************** */

#define SCALE 32768.0
extern int rand1(); /* extern keyword is optional */
int rand2(limit) int limit;
   {
    float k_value;
    k_value = ( (float) rand1() / SCALE + 1.0) * limit / 2.0 + 1.0;
    return ( (int) k_value);
   }

static int randx = 1; /* external static function */
int rand1()
     {
      randx = (randx * 25173 + 13849) % 65536; /* magic fromula */
      return ( (int) randx);
     }

int srand1(x) unsigned x;
    {
     randx = x;
    }
