/* ================================================================ */
/* The CITY Benchmark Load Tables Program.			    */
/* This Program Loads DB100, DB200, DB300 and DBUPD.	 	    */
/* 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 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 */

     long  DB_Size; /* DATABASE SIZE */

      /* 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 ql_count_err[71] =
{"An error occurred during counting rows in DB100.                      "};

  static char row_insrt_err1[71] =
{"An error occurred during Table DB100 loading.                         "};

  static char row_insrt_err2[71] =
{"An error occurred during Table DB200 loading.                         "};

  static char row_insrt_err3[71] =
{"An error occurred during Table DB300 loading.                         "};

  static char row_insrt_erri[71] =
{"An error occurred during Table DBINS loading.                         "};

  static char row_insrt_erru[71] =
{"An error occurred during Table DBUPD loading.                         "};


/* ====================================== */
/* 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");


     /* ================================= */
     /* Count Number of Rows in Tables	  */
     /* ================================= */

    strcpy(error_message,ql_count_err);
    EXEC SQL WHENEVER SQLERROR GOTO SQL_error_routine;
    EXEC SQL SELECT COUNT (DISTINCT (DB1FI1))
	     INTO   :DB_Size
	     FROM DB100;

    if (DB_Size < 1)
       { /* if DB_Size < 1 end */
	printf("\n\n* ====================================== *\n");
	printf("* The test database is empty.            *\n");
	printf("* ====================================== *\n");
       } /* if DB_Size < 1 end */

     /* ================================= */
     /* Get Number of Rows To be Inserted */
     /* ================================= */

    printf("Current database size in rows is: %d.\n", DB_Size);

    Rows_Start = DB_Size;

Get_Size:
    printf("Please enter number of rows to be added to the test database: ");
    scanf("%lu",&Rows_End);
    if (Rows_End < 1)
       { /* if DB_Size < 1 end */
	printf("\n* ============================================ *\n");
	printf("* Number of added rows must be greater than 1. *\n");
	printf("* ============================================ *\n");
	goto Get_Size;
       } /* if DB_Size < 1 end */



/* ===================================================================== */
/* The main loop start. 						 */
/* ===================================================================== */

r_100 = Rows_Start;
r_10  = Rows_Start;
r_1   = Rows_Start;


   for (ROWS = (Rows_Start+1); ROWS < (Rows_Start+Rows_End+1); ROWS++)
       { /* The main loop start */


/* ===================================================================== */
/* Load Tables Section. This section ends with commit insert rows.       */
/* ===================================================================== */

   /* ================================ */
   /* Loop for rows repeated 100 times */
   /* ================================ */

   for (i3 = 0; i3 < NLETTERS; ++i3)
       { /* for i3 start */

	++r_100; /* Integer Value Repeated 100 times. */


   /* =============================== */
   /* Loop for rows repeated 10 times */
   /* =============================== */

    for (i2 = 0; i2 < NLETTERS; ++i2)
        { /* for i2 start */

	++r_10; /* Integer Value Repeated 100 times. */

   /* ============================== */
   /* Loop for rows with unique key. */
   /* ============================== */

    for ( i1 = 0; i1 < NLETTERS; ++i1)
	{ /* for i1 start */

	 ++r_1;

 /* ============================================ */
 /* Insert a Row In DB100 and check error then   */
 /* Commit Work and Program Termination section. */
 /* ============================================ */

   EXEC SQL WHENEVER SQLERROR GOTO SQL_error_routine;

   strcpy(error_message,row_insrt_err1);
   EXEC SQL INSERT INTO
	DB100  (db1fc1,db1fi1,db1fc2,
		db1fl1,db1fr1,db1fd1,db1fv1)
	VALUES (:Char1field1, :r_1, :Char2field1,
		:vl, :vf, :vd, :Varfield1);

    printf("* =============================================== *\n");
    printf("* Row Number: %7d Has Been Inserted in DB100. *\n",r_1);


/* ============================================ */
/* Insert a Row In DB200 and check error then   */
/* Commit Work and Program Termination section. */
/* ============================================ */

   strcpy(error_message,row_insrt_err2);
   EXEC SQL INSERT INTO
	DB200  (db2fc1,db2fi1,db2fc2,
		db2fl1,db2fr1,db2fd1,db2fv1,
		db2fc3,db2fi2,db2fc4,
		db2fl2,db2fr2,db2fd2,db2fv2)
	VALUES (:Char1field1, :r_1, :Char2field1,
		:vl, :vf, :vd, :Varfield1,
		:Char1field1, :r_10, :Char2field1,
		:vl, :vf, :vd, :Varfield1);

    printf("* Row Number: %7d Has Been Inserted in DB200. *\n",r_1);


/* ============================================ */
/* Insert a Row In DB300 and check error then   */
/* Commit Work and Program Termination section. */
/* ============================================ */

   strcpy(error_message,row_insrt_err3);
   EXEC SQL INSERT INTO
	DB300  (db3fc1,db3fi1,db3fc2,
		db3fl1,db3fr1,db3fd1,db3fv1,
		db3fc3,db3fi2,db3fc4,
		db3fl2,db3fr2,db3fd2,db3fv2,
		db3fc5,db3fi3,db3fc6,
		db3fl3,db3fr3,db3fd3,db3fv3)
	VALUES (:Char1field1, :r_1, :Char2field1,
		:vl, :vf, :vd, :Varfield1,
		:Char1field1, :r_10, :Char2field1,
		:vl, :vf, :vd, :Varfield1,
		:Char1field1, :r_100, :Char2field1,
		:vl, :vf, :vd, :Varfield1);

    printf("* Row Number: %7d Has Been Inserted in DB300. *\n",r_1);

/* ============================================ */
/* Insert a Row In DBUPD and check error then   */
/* Commit Work and Program Termination section. */
/* ============================================ */

   strcpy(error_message,row_insrt_erru);
   EXEC SQL INSERT INTO
	DBUPD  (dbufc1,dbufi1,dbufc2,
		dbufl1,dbufr1,dbufd1,dbufv1,
		dbufc3,dbufi2,dbufc4,
		dbufl2,dbufr2,dbufd2,dbufv2)
	VALUES (:Char1field1, :r_1, :Char2field1,
		:vl, :vf, :vd, :Varfield1,
		:Char1field1, :r_10, :Char2field1,
		:vl, :vf, :vd, :Varfield1);

    printf("* Row Number: %7d Has Been Inserted in DBUPD. *\n",r_1);

/* ========================================= */
/* Commit Work to Complete INSERT Rows part. */
/* ========================================= */

    EXEC SQL COMMIT WORK;

    if ( r_1 == (Rows_Start+Rows_End) ) goto End_of_load_routine;


			       }  /* for i1 end */
                             }  /* for i2 end */
			   }  /* for i3 end */
		       }     /* for (ROWS = Rows_Start	end */



/* ========================================= */
/* Commit Work to Complete INSERT Rows part. */
/* ========================================= */

End_of_load_routine:
    EXEC SQL COMMIT WORK;
    printf("\n* ========================================= *\n");
    printf("* The Data Load Part Terminated 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;
    }
