/* @(#)parse_schema.c 2.1 93/05/18 */ /******************************************************************************/ /* function : parse_schema */ /* */ /* subsystem : chgen */ /* */ /* input : */ /* */ /* output : */ /* */ /* returns : void, exits on fatal schema errors. */ /* */ /* author : Steve Smith / Craig Smith */ /* */ /* created : July, 1991 */ /* */ /* revisions : 93s523: Added code to incorporate integer keys: */ /* table abbrev size must match hcg_abbr_size, commands are */ /* modified to work with abbrev's of size hcg_abbr_size. */ /* */ /* description : This routine will read the schema file line at a time, pars- */ /* ing table and field data, and loading it into memory linked */ /* lists of structures. The tt linked list holds table-level */ /* data, such as name, abbrev, etc... Within each tt list elt */ /* is another linked list, ta, which holds field-level data. */ /* The parser itself is implemented as a simple state machine */ /* with 3 states. In the NULL State, the file read is between */ /* tables. Comments between tables are ignored. When a new */ /* tables definition starts, its data is parsed, a new tt */ /* list element is allocated and filled in, and the state is */ /* changed to STARTED. In this state, the only valid item to */ /* be parsed is the tables starting "{" symbol, and the state */ /* is then changed to WITHIN. In this state individual field */ /* definitions are parsed. The state is changed back to NULL */ /* when the tables closing "}" is parsed. As each field is */ /* found, a new ta list element is allocated, filled in, and */ /* added to the current tt elements ta list. Within each parse */ /* phase, basic syntactic checks are applied, and errors may */ /* be issued. When foreign keys are found, the parent/child */ /* and child/parent relationship is logged to the pc and cp */ /* tables respectively via the add_pc_cp_entries() routine. */ /* In addition, when primary keys are found, appropriate entries*/ /* are added to the TINDEX array, which is used by the access- */ /* macro generation routines. */ /* */ /******************************************************************************/ /*****************************************************************************/ /* CHGEN V9.0 94sgen - mcook, hsano, jhyun */ /* */ /* */ /* Basic enhancements include the ability to read in both a gendb and a */ /* schema file, by specifying a command line switch. */ /* */ /* Revision history: */ /* */ /* 5/06/99 - kspinney Added TT_to_tt(), mystrcpy2(), dump_tt_ta_data(), */ /* jkarner and dump_tt_ta_data() to support the parsing of an */ /* input schema in .dat (.msdat) format */ /* 5/18/94 - mcook - Changed around the header to the metaschema.dat file */ /* to reflect an actual table type. */ /* Changed fkey naming conventions to TTid, TTid2, */ /* TTid3... instead of TTid, TT02, TT03... */ /* Changed CHGEN-F-NOPATHS to CHGEN-W-NOPATHS (i.e. from*/ /* a fatal error to a warning. */ /* */ /* 5/16/94 - mcook - Added error checking: */ /* CHGEN-F-ERRNOPARENT - Searches for the parent */ /* referenced in a relation and does not come up with a */ /* matching parent, (this limits the schema to not allow*/ /* forward references.) */ /* genDB parsing: Parsed out parent references. */ /* */ /* 5/15/94 - mcook - Bug fixes: Fixed the case of multiple references to */ /* the same primary key by adding table name plus a */ /* number which gets incremented per reference. */ /* */ /* 5/13/94 - mcook - Added the filename to the datafile, and changed the */ /* title of the datafile to reflect where it is coming */ /* from. Tried to add date and time stamping, but it */ /* always returned the same (wrong) date and time. */ /* */ /* 5/12/94 - mcook - Added error checking: */ /* CHGEN-F-NOPATHS - Signifying that the genDB schema */ /* line "create path" is not supported in this */ /* version if chgen. */ /* CHGEN-F-ERROPENMSFILE - Signifying that the datafile */ /* could not be opened properly. */ /* */ /* 5/10/94 - mcook - Added the function Output_MetaSchema(), which reads */ /* the TT and TA tables and outputs them to a file if */ /* the command line qualifier "-datafile=" was */ /* specified with a filename. */ /* */ /* 5/04/94 - mcook - genDB parsing: Created a primary_key line, which is */ /* the first line in a chgen schema table--but does not */ /* exist in the current genDB schema, from the table */ /* name and abbreviation. */ /* */ /* 5/01/94 - mcook - Added the ability to read in either a chgen or a */ /* gendb schema file by specifying a command line */ /* switch "-gendbschema" */ /* */ /* 4/26/94 - mcook - genDB parsing: Parsed out "create table" to */ /* determine start of a new table. */ /*****************************************************************************/ #include #include #include /* string.h include added by genlog team 96s523 to suppress error message */ #include #include "chgen_define.h" #include "chgen_externs.h" #include "prototypes.h" int cfkey; char lastfkey[NAMELENGTH]; void parse_schema_chgen(); /* forward declaration - genMerge 99s523 */ void parse_schema_gendb(); /* forward declaration - genMerge 99s523 */ void find_parent (char* tbuffer); /* forward declaration - genMerge 99s523 */ void TT_to_tt(); /* forward declaration - genMerge 99s523 */ void parse_schema_dat(); /* forward declaration - genMerge 99s523 */ void dump_tt_ta_data(); /* forward declaration - genMerge 99s523 */ void mystrcpy2(char *s,char *t,int n); /* forward declaration - genMerge 99s523 */ void parse_schema() { static char rcsid[] = "$Id: parse_schema.c,v 1.4.4.2 1999/05/07 01:25:18 jkarner Exp $"; if (cli_gendbschema) parse_schema_gendb(); else if (!cli_datinput) parse_schema_chgen(); else parse_schema_dat(); } void parse_schema_chgen() { struct rr_type *obj_ptr ; int idx; int parse_state; char is_key[10]; tt = NULL; tt_curr = NULL; tab_seq_no = 0 ; num_tables = 0; parse_state = state_NULL; strcpy(tab_name,""); strcpy(tab_abbr,""); strcpy(field_name,""); strcpy(is_key,"0"); comment[0] = '\0'; read_next(); while ( !feof ( schtxt_fp ) ) { idx = 0; hcg_parse(buffer,temp_buffer,&idx); if (temp_buffer[0] == '\0') /* blank line */ { read_next(); continue; } if (strncmp(temp_buffer,"/*",2) == 0) /* comment is only thing on line, ignore */ { read_next(); continue; } switch (parse_state) { case state_NULL : /* expecting start of a new table */ if (temp_buffer[0] == '{') { printf("CHGEN-F-MISSINGTBLLINE, found '{' when expecting the start of a new table, last table processed was %s\n", tab_name); exit(1); } if (temp_buffer[0] == '}') { printf("CHGEN-F-EXTRAEND, found an extra '}' when expecting the start of a new table, last table processed was %s\n", tab_name); exit(1); } if (!isalpha(temp_buffer[0])) { printf("CHGEN-F-BADTBLNAME, invalid table name %s, must start with an alphabetic character\n",temp_buffer); exit(1); } if (strlen(temp_buffer) > NAMELENGTH) { printf("CHGEN-F-NAMETOOLONG, table name %s exceeds the maximum length of %d\n", temp_buffer,NAMELENGTH-1); exit(1); } strcpy(tab_name,temp_buffer); hcg_parse(buffer,temp_buffer,&idx); if (strlen(temp_buffer) != hcg_abbr_size) { printf("CHGEN-F-NAMETOOLONG, table abbreviation (%s) for table %s must be %d characters long\n", temp_buffer,tab_name, hcg_abbr_size); exit(1); } strcpy(tab_abbr,temp_buffer); { int i; for(i=0; i < hcg_abbr_size; i++) tab_abbr[i] = isupper(tab_abbr[i]) ? tab_abbr[i] : toupper(tab_abbr[i]); } if (strncmp(buffer+idx,"/*",2) != 0) { if (!cli_quiet) printf("CHGEN-W-MISSINGCOMMENT, table %s does not have a comment\n",tab_name); comment[0] = '\0'; } else { mystrcpy(comment, buffer+idx, MAXCOMMENTLENGTH,1); } /******************************************/ /* Starting a new table, so add a node to */ /* the tt list. */ /******************************************/ tt_tmp = (struct tt_type*) malloc (sizeof (struct tt_type)); strcpy(tt_tmp->TTabbr,tab_abbr); strcpy(tt_tmp->TableName,tab_name); strcpy(tt_tmp->comment,comment); tt_tmp->next_ptr = NULL; tt_tmp->ta_ptr = NULL; num_tables++; if (tt == NULL) { tt = tt_tmp; tt_curr = tt_tmp; } else { tt_curr->next_ptr = tt_tmp; tt_curr = tt_curr->next_ptr; } parse_state = state_STARTED; read_next(); break ; case state_STARTED : /* expecting '{' symbol */ if (temp_buffer[0] != '{') { printf("CHGEN-F-MISSINGBEGIN, missing '{' for table %s\n",tab_name); exit(1); } parse_state = state_WITHIN; read_next(); break ; case state_WITHIN : /* expecting data-field line */ if (temp_buffer[0] == '}') /* done with this table */ { tab_seq_no++; parse_state = state_NULL; read_next(); break ; } if (temp_buffer[0] == '{') { printf("CHGEN-F-EXTRABEGIN, extra '{' found for table %s\n",tab_name); exit(1); } if (!isalpha(temp_buffer[0])) { printf("CHGEN-F-BADFIELDNAME, invalid field name %s for table %s, must start with an alphabetic character\n", temp_buffer,tab_name); exit(1); } if (strlen(temp_buffer) > NAMELENGTH) { printf("CHGEN-F-NAMETOOLONG, field name %s for table %s exceeds the maximum length of %d\n", temp_buffer,tab_name,NAMELENGTH-1); exit(1); } strcpy(field_name,temp_buffer); hcg_parse(buffer,temp_buffer,&idx); if (strlen(temp_buffer) > NAMELENGTH) { printf("CHGEN-F-NAMETOOLONG, alternate field name %s for field %s in table %s exceeds the maximum length of %d\n", temp_buffer,field_name,tab_name,NAMELENGTH-1); exit(1); } strcpy(alt_field_name,temp_buffer); hcg_parse(buffer,temp_buffer,&idx); if (strlen(temp_buffer) > TYPELENGTH) { printf("CHGEN-F-TYPETOOLONG, data-type %s for field %s in table %s exceeds the maximum length of %d\n", temp_buffer,field_name,tab_name,NAMELENGTH-1); exit(1); } switch (temp_buffer[0]) { case 'i': if ((strcmp(temp_buffer+1,"2") != 0) && (strcmp(temp_buffer+1,"4") != 0)) { if (!cli_quiet) printf("CHGEN-W-BADINTTYPE, integer data-type %s for field %s in table %s is invalid, value types are i2 and i4\n", temp_buffer,field_name,tab_name); } break; case 'f': if ((strcmp(temp_buffer+1,"4") != 0) && (strcmp(temp_buffer+1,"8") != 0)) { if (!cli_quiet) printf("CHGEN-W-BADFLOATTYPE, float data-type %s for field %s in table %s is invalid, value types are f4 and f8\n", temp_buffer,field_name,tab_name); } break; case 'd': if (strcmp(temp_buffer+1,"ate") != 0) { printf("CHGEN-F-BADDATE, data-type %s for field %s in table %s is not a valid date type\n", temp_buffer,field_name,tab_name); exit(1); } break; case 'c': case 't': if (atoi(temp_buffer+1) <= 0) { printf("CHGEN-F-CHARTEXT, char/text data-type %s for field %s in table %s has an invalid length specifier\n", temp_buffer,field_name,tab_name); exit(1); } break; default: { printf("CHGEN-F-BADTYPE, unsupported data-type %s specified for field %s in table %s\n", temp_buffer,field_name,tab_name); exit(1); } } /* switch */ strcpy(data_type,temp_buffer); hcg_parse(buffer,temp_buffer,&idx); if ((strcmp(temp_buffer,"0") != 0) && (strcmp(temp_buffer,"1") != 0) && (strcmp(temp_buffer,"s") != 0) && (strcmp(temp_buffer,"-1") != 0)) { printf("CHGEN-F-BADISKEY, 'is-key' field %s for field %s in table %s must be 0, 1, -1 or s\n", temp_buffer,field_name,tab_name); exit(1); } strcpy(is_key,temp_buffer); if (is_key[0] != '0') { int i; for(i=0; ita_ptr == NULL) printf("CHGEN-F-KEYMUSTBEC8, primary key field %s for table %s must be of type c8 \n", field_name,tab_name); else printf("CHGEN-F-KEYMUSTBEC8, foreign key field %s for table %s must be of type c8 \n", field_name,tab_name); exit(1); } if (tt_curr->ta_ptr == NULL) /* first field, must be key and first 2 abbrev==tab_abbrev */ { if (is_key[0] != '1') { printf("CHGEN-F-FIRSTMUSTBEKEY, first field %s for table %s must have a 'is-key' value of 1\n", field_name,tab_name); exit(1); } if (strncmp(field_name,tab_abbr,hcg_abbr_size) != 0) { printf("CHGEN-F-PKEYABBREVNOMATCH, first %d characters of primary key field %s for table %s must equal the table abbreviation %s\n", hcg_abbr_size, field_name,tab_name,tab_abbr); exit(1); } /* get the hash_value for the tab_abbrev_name*/ /* and put correspondind tab_seq_no into */ /* field_list */ TXindex = encoding(tab_abbr); /* fill up TINDEX */ TINDEX[TXindex].TXindex = TXindex ; TINDEX[TXindex].TTindex = tab_seq_no; strcpy(TINDEX[TXindex].TTabbr, tab_abbr); } /* first field, must be pkey */ else if (is_key[0] != '0') /* must be a foreign key */ { add_pc_cp_entries(field_name,tt_curr->ta_ptr->FieldName,is_key); } /***********************************************/ /* Add this field name to the ta list. */ /***********************************************/ ta_tmp = (struct ta_type*) malloc (sizeof (struct ta_type)); strcpy(ta_tmp->FieldName,field_name); strcpy(ta_tmp->AltFieldName, alt_field_name); strcpy(ta_tmp->FieldType,data_type); strcpy(ta_tmp->comment,comment); ta_tmp->IsKey = (is_key[0] != '0'); ta_tmp->HasBp = (is_key[0] == '1') || (is_key[0] == 's'); ta_tmp->Singleton = (is_key[0] == 's'); ta_tmp->next_ptr = NULL; if (tt_curr->ta_ptr == NULL) { tt_curr->ta_ptr = ta_tmp; ta_curr = ta_tmp; } else { ta_curr->next_ptr = ta_tmp; ta_curr = ta_curr->next_ptr; } parse_state = state_WITHIN; read_next(); break ; } /* switch */ } /* while !feof */ } /* end func */ void create_primary_key() { char is_key[10]; strcpy(field_name, tab_abbr); strcat(field_name, "id"); strcpy(alt_field_name, tab_name); strcat(alt_field_name, "_id"); strcpy(data_type, "c8"); strcpy(is_key, "1"); strcpy(comment, "/* primary key field */"); if (is_key[0] != '0') { int i; for(i=0; ita_ptr == NULL) /* first field, must be key and first 2 abbrev==tab_abbrev */ { if (is_key[0] != '1') { printf("CHGEN-F-FIRSTMUSTBEKEY, first field %s for table %s must have a 'is-key' value of 1\n", field_name,tab_name); exit(1); } if (strncmp(field_name,tab_abbr,hcg_abbr_size) != 0) { printf("CHGEN-F-PKEYABBREVNOMATCH, first %d characters of primary key field %s for table %s must equal the table abbreviation %s\n", hcg_abbr_size, field_name,tab_name,tab_abbr); exit(1); } /* get the hash_value for the tab_abbrev_name*/ /* and put correspondind tab_seq_no into */ /* field_list */ TXindex = encoding(tab_abbr); /* fill up TINDEX */ TINDEX[TXindex].TXindex = TXindex ; TINDEX[TXindex].TTindex = tab_seq_no; strcpy(TINDEX[TXindex].TTabbr, tab_abbr); } /* first field, must be pkey */ else if (is_key[0] != '0') /* must be a foreign key */ { add_pc_cp_entries(field_name,tt_curr->ta_ptr->FieldName,is_key); } /***********************************************/ /* Add this field name to the ta list. */ /***********************************************/ ta_tmp = (struct ta_type*) malloc (sizeof (struct ta_type)); strcpy(ta_tmp->FieldName,field_name); strcpy(ta_tmp->AltFieldName,alt_field_name); strcpy(ta_tmp->FieldType,data_type); strcpy(ta_tmp->comment,comment); ta_tmp->IsKey = (is_key[0] != '0'); ta_tmp->HasBp = (is_key[0] == '1') || (is_key[0] == 's'); ta_tmp->Singleton = (is_key[0] == 's'); ta_tmp->next_ptr = NULL; if (tt_curr->ta_ptr == NULL) { tt_curr->ta_ptr = ta_tmp; ta_curr = ta_tmp; } else { ta_curr->next_ptr = ta_tmp; ta_curr = ta_curr->next_ptr; } read_next(); } void parse_schema_gendb() { struct rr_type *obj_ptr ; int idx, x, y; int parse_state; char is_key[10]; char tempstr2[TYPELENGTH]; char* tempstr; int primary; tt = NULL; tt_curr = NULL; tab_seq_no = 0 ; num_tables = 0; parse_state = state_NULL; strcpy(tab_name,""); strcpy(tab_abbr,""); strcpy(field_name,""); strcpy(is_key,"0"); comment[0] = '\0'; primary = FALSE; read_next(); while ( !feof ( schtxt_fp ) ) { idx = 0; hcg_parse(buffer,temp_buffer,&idx); if (temp_buffer[0] == '\0') /* blank line */ { read_next(); continue; } if (strncmp(temp_buffer,"/*",2) == 0) /* comment is only thing on line, ignore */ { read_next(); continue; } switch (parse_state) { case state_NULL : /* expecting start of a new table */ if (temp_buffer[0] == '{') { printf("CHGEN-F-MISSINGTBLLINE, found '{' when expecting the start of a new table, last table processed was %s\n", tab_name); exit(1); } if (temp_buffer[0] == '}') { printf("CHGEN-F-EXTRAEND, found an extra '}' when expecting the start of a new table, last table processed was %s\n", tab_name); exit(1); } /* Reads in 'create table' from the schema to indicate the beginning of a new table definition */ if (strcmp(temp_buffer, "create")) { printf ("CHGEN-F-MISSINGTBLSTART, expecting start of table 'create table' not found\n"); exit (1); } hcg_parse(buffer,temp_buffer,&idx); if (strcmp(temp_buffer, "path") == 0) { if (!cli_quiet) printf ("CHGEN-W-NOPATHS, paths are not supported in this version of chgen.\n"); read_next(); break; } if (strcmp(temp_buffer, "table")) { printf ("CHGEN-F-MISSINGTBLSTART, expecting start of table 'create table' not found\n"); exit (1); } hcg_parse(buffer,temp_buffer,&idx); if (!isalpha(temp_buffer[0])) { printf("CHGEN-F-BADTBLNAME, invalid table name %s, must start with an alphabetic character\n",temp_buffer); exit(1); } if (strlen(temp_buffer) > NAMELENGTH) { printf("CHGEN-F-NAMETOOLONG, table name %s exceeds the maximum length of %d\n", temp_buffer,NAMELENGTH-1); exit(1); } strcpy(tab_name,temp_buffer); hcg_parse(buffer,temp_buffer,&idx); if (strlen(temp_buffer) != hcg_abbr_size) { printf("CHGEN-F-NAMETOOLONG, table abbreviation (%s) for table %s must be %d characters long\n", temp_buffer,tab_name, hcg_abbr_size); exit(1); } strcpy(tab_abbr,temp_buffer); { int i; for(i=0; i < hcg_abbr_size; i++) tab_abbr[i] = isupper(tab_abbr[i]) ? tab_abbr[i] : toupper(tab_abbr[i]); } if (strncmp(buffer+idx,"/*",2) != 0) { if (!cli_quiet) printf("CHGEN-W-MISSINGCOMMENT, table %s does not have a comment\n",tab_name); comment[0] = '\0'; } else { mystrcpy(comment, buffer+idx, MAXCOMMENTLENGTH,1); } /******************************************/ /* Starting a new table, so add a node to */ /* the tt list. */ /******************************************/ tt_tmp = (struct tt_type*) malloc (sizeof (struct tt_type)); strcpy(tt_tmp->TTabbr,tab_abbr); strcpy(tt_tmp->TableName,tab_name); strcpy(tt_tmp->comment,comment); tt_tmp->next_ptr = NULL; tt_tmp->ta_ptr = NULL; num_tables++; if (tt == NULL) { tt = tt_tmp; tt_curr = tt_tmp; } else { tt_curr->next_ptr = tt_tmp; tt_curr = tt_curr->next_ptr; } cfkey = 0; parse_state = state_STARTED; read_next(); break ; case state_STARTED : /* expecting '{' symbol */ if (temp_buffer[0] != '{') { printf("CHGEN-F-MISSINGBEGIN, missing '{' for table %s\n",tab_name); exit(1); } parse_state = state_WITHIN; create_primary_key(); break ; case state_WITHIN : /* expecting data-field line */ if (temp_buffer[0] == '}') /* done with this table */ { tab_seq_no++; parse_state = state_NULL; read_next(); break ; } if (temp_buffer[0] == '{') { printf("CHGEN-F-EXTRABEGIN, extra '{' found for table %s\n",tab_name); exit(1); } if (strlen(temp_buffer) > NAMELENGTH) { printf("CHGEN-F-NAMETOOLONG, alternate field name %s for field %s in table %s exceeds the maximum length of %d\n", temp_buffer,field_name,tab_name,NAMELENGTH-1); exit(1); } strcpy(alt_field_name,temp_buffer); hcg_parse(buffer,temp_buffer,&idx); strcpy (field_name, ""); if (temp_buffer[0] != 'p') { if (strlen (alt_field_name) < 5) { strncpy(field_name, alt_field_name, strlen(alt_field_name)); } else { field_name[0] = alt_field_name[0]; field_name[1] = '\0'; /* added the cast for OSF maldred 22-Nov-95 */ if ((tempstr = (char *)strstr (alt_field_name, "_")) != NULL) { tempstr++; strcat (field_name, tempstr); } else { strncpy (field_name, alt_field_name, 5); field_name[5] = '\0'; } } primary = FALSE; } else { find_parent (temp_buffer); primary = TRUE; strcpy (temp_buffer, "c(8)"); } if (strlen(temp_buffer) > TYPELENGTH) { printf("CHGEN-F-TYPETOOLONG, data-type %s for field %s in table %s exceeds the maximum length of %d\n", temp_buffer,field_name,tab_name,NAMELENGTH-1); exit(1); } strcpy (tempstr2, temp_buffer); x = 0; y = 0; while (tempstr2[x] != NULL) { if ((tempstr2[x] != '(') && (tempstr2[x] != ')')) { temp_buffer[y] = tempstr2[x]; y++; } x++; } temp_buffer[y] = '\0'; switch (temp_buffer[0]) { case 'i': if ((strcmp(temp_buffer+1,"2") != 0) && (strcmp(temp_buffer+1,"4") != 0)) { if (!cli_quiet) printf("CHGEN-W-BADINTTYPE, integer data-type %s for field %s in table %s is invalid, value types are i2 and i4\n", temp_buffer,field_name,tab_name); } break; case 'f': if ((strcmp(temp_buffer+1,"4") != 0) && (strcmp(temp_buffer+1,"8") != 0)) { if (!cli_quiet) printf("CHGEN-W-BADFLOATTYPE, float data-type %s for field %s in table %s is invalid, value types are f4 and f8\n", temp_buffer,field_name,tab_name); } break; case 'd': if (strcmp(temp_buffer+1,"ate") != 0) { printf("CHGEN-F-BADDATE, data-type %s for field %s in table %s is not a valid date type\n", temp_buffer,field_name,tab_name); exit(1); } break; case 'c': case 't': if (atoi(temp_buffer+1) <= 0) { printf("CHGEN-F-CHARTEXT, char/text data-type %s for field %s in table %s has an invalid length specifier\n", temp_buffer,field_name,tab_name); exit(1); } break; default: { printf("CHGEN-F-BADTYPE, unsupported data-type %s specified for field %s in table %s\n", temp_buffer,field_name,tab_name); exit(1); } } /* switch */ strcpy(data_type,temp_buffer); /* hcg_parse(buffer,temp_buffer,&idx); if ((strcmp(temp_buffer,"0") != 0) && (strcmp(temp_buffer,"1") != 0) && (strcmp(temp_buffer,"s") != 0) && (strcmp(temp_buffer,"-1") != 0)) { printf("CHGEN-F-BADISKEY, 'is-key' field %s for field %s in table %s must be 0, 1, -1 or s\n", temp_buffer,field_name,tab_name); exit(1); } */ if (primary) strcpy(is_key, "1"); else strcpy(is_key, "0"); if (is_key[0] != '0') { int i; for(i=0; ita_ptr == NULL) printf("CHGEN-F-KEYMUSTBEC8, primary key field %s for table %s must be of type c8 \n", field_name,tab_name); else printf("CHGEN-F-KEYMUSTBEC8, foreign key field %s for table %s must be of type c8 \n", field_name,tab_name); exit(1); } if (tt_curr->ta_ptr == NULL) /* first field, must be key and first 2 abbrev==tab_abbrev */ { if (is_key[0] != '1') { printf("CHGEN-F-FIRSTMUSTBEKEY, first field %s for table %s must have a 'is-key' value of 1\n", field_name,tab_name); exit(1); } if (strncmp(field_name,tab_abbr,hcg_abbr_size) != 0) { printf("CHGEN-F-PKEYABBREVNOMATCH, first %d characters of primary key field %s for table %s must equal the table abbreviation %s\n", hcg_abbr_size, field_name,tab_name,tab_abbr); exit(1); } /* get the hash_value for the tab_abbrev_name*/ /* and put correspondind tab_seq_no into */ /* field_list */ TXindex = encoding(tab_abbr); /* fill up TINDEX */ TINDEX[TXindex].TXindex = TXindex ; TINDEX[TXindex].TTindex = tab_seq_no; strcpy(TINDEX[TXindex].TTabbr, tab_abbr); } /* first field, must be pkey */ else if (is_key[0] != '0') /* must be a foreign key */ { add_pc_cp_entries(field_name,tt_curr->ta_ptr->FieldName,is_key); } /***********************************************/ /* Add this field name to the ta list. */ /***********************************************/ ta_tmp = (struct ta_type*) malloc (sizeof (struct ta_type)); /* Decided to swap the alternate field name with the field name, so that it would be unique. (For non-primary keys) */ if (!primary) { strcpy(ta_tmp->FieldName,alt_field_name); strcpy(ta_tmp->AltFieldName, field_name); } else { strcpy(ta_tmp->FieldName,field_name); strcpy(ta_tmp->AltFieldName, alt_field_name); } strcpy(ta_tmp->FieldType,data_type); strcpy(ta_tmp->comment,comment); ta_tmp->IsKey = (is_key[0] != '0'); ta_tmp->HasBp = (is_key[0] == '1') || (is_key[0] == 's'); ta_tmp->Singleton = (is_key[0] == 's'); ta_tmp->next_ptr = NULL; if (tt_curr->ta_ptr == NULL) { tt_curr->ta_ptr = ta_tmp; ta_curr = ta_tmp; } else { ta_curr->next_ptr = ta_tmp; ta_curr = ta_curr->next_ptr; } parse_state = state_WITHIN; read_next(); break ; } /* switch */ } /* while !feof */ } /* end func */ void find_parent (char* tbuffer) { struct tt_type* ttemp; char tablename[NAMELENGTH]; int x = 0; char numbuffer[10]; tbuffer += 7; while (tbuffer[x] != ',') { tablename[x] = tbuffer[x]; x++; } tablename[x] = '\0'; tbuffer += (x + 1); strcpy (field_name, ""); ttemp = tt; cfkey++; while (ttemp != NULL) { if (strcmp (ttemp->TableName, tablename) == 0) { strcpy (field_name, ttemp->TTabbr); if (strcmp (field_name, lastfkey) != 0) cfkey = 1; strcpy (lastfkey, field_name); strcat (field_name, "id"); if (cfkey > 1) { sprintf (numbuffer, "%d", cfkey); strcat (field_name, numbuffer); } } ttemp = ttemp->next_ptr; } if (strcmp (field_name, "") == 0) { printf ("CHGEN-F-ERRNOPARENT, Could not locate parent %s for relation.\n", tablename); exit (1); } x = 0; while (tbuffer[x] != ',') { alt_field_name[x] = tbuffer[x]; x++; } alt_field_name[x] = '\0'; tbuffer += (x + 1); if ((atoi(tbuffer) != 0) && (atoi(tbuffer) != 1)) printf ("CHGEN-W-PRNTCARD, Could not determine parent cardinality.\n"); tbuffer += 2; if (atoi(tbuffer) < 0) printf ("CHGEN-W-CHILDCARD, Invalid child cardinality, must be a greater than or equal to 0.\n"); } void Output_MetaSchema () { FILE *fp; struct tt_type* ttemp; struct ta_type* tatemp; int tcount = 1; int acount = 1; if ((fp = fopen (datafile, "w")) == NULL) { printf ("CHGEN-F-ERROPENMSFILE, Cannot open %s. Check filename and rerun program.\n"); exit (1); } fprintf (fp, "SV010001\tPJ010001\t%s\tCHGEN v9.0\t", sch_text_file_name); if (!cli_gendbschema) fprintf (fp, "CHGEN\n"); else fprintf (fp, "GENDB\n"); ttemp = tt; while (ttemp != NULL) { fprintf (fp, "TT0%d SV010001 ", 10000+tcount); fprintf (fp, "%s %s %s\n", ttemp->TTabbr, ttemp->TableName, ttemp->comment); tcount++; ttemp = ttemp->next_ptr; } tcount = 1; ttemp = tt; acount = 1; while (ttemp != NULL) { tatemp = ttemp->ta_ptr; fprintf (fp, "\n"); while (tatemp != NULL) { fprintf (fp, "TA0%d TT0%d ", 10000+acount, 10000+tcount); fprintf (fp, "%s %s %s ", tatemp->FieldName, tatemp->AltFieldName, tatemp->FieldType); if (tatemp->Singleton) fprintf (fp, "s"); else if (tatemp->HasBp) fprintf (fp, "1"); else if (tatemp->IsKey && !tatemp->HasBp) fprintf (fp, "-1"); else fprintf (fp, "0"); fprintf (fp, " %s\n", tatemp->comment); acount++; tatemp = tatemp->next_ptr; } tcount++; ttemp = ttemp->next_ptr; } fclose (fp); } void parse_schema_dat() { pr_init(sch_viewdef_file_name,sch_text_file_name); pr_load(view_name, sch_text_file_name); if (cli_datafile) pr_dump(view_name, datafile, 0, "w"); TT_to_tt(); } void TT_to_tt() { int parse_state; char is_key[10]; int i; char parent[NAMELENGTH]; char child[NAMELENGTH]; tt = NULL; tt_curr = NULL; tab_seq_no = 0 ; num_tables = 0; strcpy(tab_name,""); strcpy(tab_abbr,""); strcpy(field_name,""); strcpy(is_key,"0"); comment[0] = '\0'; lut_init(&hcg_table_abbrev_lut,ABBR_TBL_TYPE); for ( TTcurr = TT; TTcurr; TTcurr = TTcurr->next_ptr) { /******************************************/ /* Starting a new table, so add a node to */ /* the tt list. */ /******************************************/ tt_tmp = (struct tt_type*) malloc (sizeof (struct tt_type)); mystrcpy2(tt_tmp->TTabbr,TTcurr->ttabb,HCG_ABBR_SIZE); mystrcpy2(tt_tmp->TableName,TTcurr->ttname,NAMELENGTH); mystrcpy(tt_tmp->comment,TTcurr->descr,MAXCOMMENTLENGTH,1); tt_tmp->next_ptr = NULL; tt_tmp->ta_ptr = NULL; num_tables++; if (tt == NULL) { tt = tt_tmp; tt_curr = tt_tmp; } else { tt_curr->next_ptr = tt_tmp; tt_curr = tt_curr->next_ptr; } for (TAcurr = TTcurr->TAid_fcp; TAcurr; TAcurr = TAcurr->next_ptr) { if (TAcurr->TTid_pp != TTcurr) /* this handles all but the last TT */ continue; /* (the for loop terminates at the last TT) */ if (tt_curr->ta_ptr == NULL) { /* first field, must be key and first 2 abbrev==tab_abbrev */ /* get the hash_value for the table abbreviation */ /* and put corresponding tab_seq_no into field_list */ TXindex = encoding(tt_curr->TTabbr); /* fill up TINDEX */ TINDEX[TXindex].TXindex = TXindex ; TINDEX[TXindex].TTindex = tab_seq_no; mystrcpy2(TINDEX[TXindex].TTabbr, TTcurr->ttabb,HCG_ABBR_SIZE); } else if (TAcurr->iskey[0] != '0') { /* must be a foreign key */ mystrcpy2 (parent, TAcurr->fname, NAMELENGTH); mystrcpy2 (child , TTcurr->TAid_fcp->fname, NAMELENGTH); add_pc_cp_entries( parent, child, TAcurr->iskey); } /***********************************************/ /* Add this field name to the ta list. */ /***********************************************/ ta_tmp = (struct ta_type*) malloc (sizeof (struct ta_type)); mystrcpy2(ta_tmp->FieldName,TAcurr->fname,NAMELENGTH); mystrcpy2(ta_tmp->AltFieldName, TAcurr->dfltVal,NAMELENGTH); mystrcpy2(ta_tmp->FieldType, TAcurr->ftype,NAMELENGTH); mystrcpy(ta_tmp->comment,TAcurr->comment,MAXCOMMENTLENGTH,1); ta_tmp->IsKey = (TAcurr->iskey[0] != '0'); ta_tmp->HasBp = (TAcurr->iskey[0] == '1') || (TAcurr->iskey[0] == 's'); ta_tmp->Singleton = (TAcurr->iskey[0] == 's'); ta_tmp->next_ptr = NULL; if (tt_curr->ta_ptr == NULL) { tt_curr->ta_ptr = ta_tmp; ta_curr = ta_tmp; } else { ta_curr->next_ptr = ta_tmp; ta_curr = ta_curr->next_ptr; } } /* for TA */ tab_seq_no++; } /* for TT */ } /* end func */ /* void dump_tt_ta_data() * * This function dumps out the tt/ta struct contents * * Preconditions: a global pointer to a valid tt_type structure (or a NULL pointer) * tt->next ptr is NULL for the last table type * ta->next_ptr is NULL for the last attribute of each table type * * PostConditions: contents of tt/ta structs are printed to stdout */ void dump_tt_ta_data() { for ( tt_tmp = tt; tt_tmp; tt_tmp = tt_tmp->next_ptr) { printf ("tt_tmp->TTabbr : %s\n", tt_tmp->TTabbr); printf ("tt_tmp->TableName: %s\n", tt_tmp->TableName); printf ("tt_tmp->comment : %s\n", tt_tmp->comment); printf ("tt_tmp->next_ptr : %ld\n", tt_tmp->next_ptr); printf ("tt_tmp->ta_ptr : %ld\n", tt_tmp->ta_ptr); for (ta_tmp = tt_tmp->ta_ptr; ta_tmp; ta_tmp = ta_tmp->next_ptr) { printf ("\n************** ta_tmp->FieldName = %s\n",ta_tmp->FieldName); printf ( " ta_tmp = %ld\n", ta_tmp); printf ( " ta_tmp->AltFieldName = %s\n",ta_tmp->AltFieldName); printf ( " ta_tmp->FieldType = %s\n",ta_tmp->FieldType); printf ( " ta_tmp->comment = %s\n",ta_tmp->comment ); printf ( " ta_tmp->IsKey = %d\n",ta_tmp->IsKey); printf ( " ta_tmp->HasBp = %d\n",ta_tmp->HasBp); printf ( " ta_tmp->Singleton = %d\n",ta_tmp->Singleton); printf ( " ta_tmp->next_ptr = %ld\n",ta_tmp->next_ptr); } /* for TA */ } /* for TT */ } /* end func */ void mystrcpy2(s,t,n) char *s, *t; int n; { int i; strncpy(s,t,n); for (i = 0; i < n; i++) { /* search for space or tab and replace with an EOL */ if ( (s[i] == ' ') || (s[i] == 9) ) { s[i] = '\0'; return; } } s[n] = '\0'; }