/* * Det här är filen "esql-test-4.esc". * Den innehåller ett C-program med ESQL (embedded SQL). * Programmet visar hur man kan ändra på innehållet i databasen, * med ESQL-satsen UPDATE. * Det finns fler sätt att uppdatera databasen: * dels med ESQL-satserna DELETE och INSERT, dels med hjälp av cursors. * * Thomas Padron-McCarthy IDA (tpm@ida.liu.se) * 30 december 1992, 4 oktober 1993, 25 augusti 1994 * * Instruktioner: * Kopiera filen till ditt eget directory: * cp ~di-c/kursbibliotek/esql-test-4.esc esql-test-4.esc * Studera programmet. * Kör filen genom C-ESQL-preprocessorn med kommandot * esqlc -p esql-test-4.esc * Då får du en C-fil som heter "esql-test-4.c". * Kompilera och länka ihop programmet (skriv det här som EN rad): * gcc -o esql-test-4 esql-test-4.c * /usr/local/ingres/ingres/lib/libingres.a -lm * Kör programmet: * esql-test-4 * */ #include #include #include EXEC sql include sqlca; /* WHENEVER-satsen gäller de EXEC SQL-satser som står * NEDANFÖR DEN I FILEN, inte de som "körs efter att den körts". * Vi kan alltså inte lägga in den t. ex. först i funktionen "main", * om main ligger sist i filen, för då gäller den bara i main * och inte i de andra funktionerna! */ EXEC SQL whenever sqlerror call my_ingres_error_handler; /* Den här funktionen returnerar 1 om användaren svarar 'j', 0 om 'n': */ int ask_yes_or_no(char *question) { int c; do { printf("%s (skriv 'j' eller 'n') ", question); c = getchar(); if (c != '\n') while (getchar() != '\n') ; if (c == 'j') return 1; else if (c == 'n') return 0; else { printf("\007"); printf("Nej! Fel! Skriv 'j' eller 'n' först på raden!\n"); } } while (c != 'j' && c != 'n'); } /* ask_yes_or_no */ /* En mer "praktisk" variant av funktionen "fgets": */ char *smart_fgets(char *str, int strsize, FILE *instream) { char *fgets_result; int length; fgets_result = fgets(str, strsize, instream); if (fgets_result == NULL) return NULL; length = strlen(str); if (str[length - 1] == '\n') str[length - 1] = '\0'; else if (!feof(instream)) { printf("Varning: För många tecken på raden (max antal tecken = %d).\n", strsize - 2); printf(" Överskjutande tecken kastas bort.\n"); while (getc(instream) != '\n') ; } printf("Inmatad sträng: '%s'.\n", str); return fgets_result; } /* smart_fgets */ /* Den här funktionen "kapar bort" blanktecken på slutet i en sträng: */ void skip_trailing_space(char *str) { char *cp; cp = str; while (*cp) ++cp; --cp; while (cp >= str && isspace(*cp)) --cp; cp[1] = '\0'; } /* skip_trailing_space */ /* Den här funktionen ska anropas om det uppstår ett fel i en SQL-sats: */ void my_ingres_error_handler(void) { EXEC SQL begin declare section; char the_error_message[1000]; /* Felmedelanden kan vara långa! */ EXEC SQL end declare section; EXEC SQL inquire_ingres (:the_error_message = ERRORTEXT); printf("\n"); printf("*** Tråkigt nog har det uppstått ett INGRES-fel.\n"); printf("Så här ser felmeddelandet från INGRES ut:\n"); printf("%s", the_error_message); printf("\n"); if (ask_yes_or_no("Vill du avsluta programmet?")) { printf("Jaha. Tack och adjö.\n"); if (ask_yes_or_no("Ska ändringarna kastas bort?")) { printf("Ok, i så fall gör vi en ROLLBACK nu.\n"); EXEC SQL rollback; } EXEC SQL disconnect; exit(1); } else { printf("Nähä. Då kör vi vidare!\n\n"); } } /* my_ingres_error_handler */ /* Den här funktionen skriver ut innehållet i tabellen EMPLOYEE: */ void print_employee(void) { EXEC SQL begin declare section; char this_name[20 + 1]; int this_salary; EXEC SQL end declare section; EXEC SQL declare emp_cursor cursor for select name, salary from employee; EXEC SQL open emp_cursor; printf("\n"); printf("Nu ser tabellen över anställda ut så här:\n"); printf("-----------------------------------------\n"); while (sqlca.sqlcode == 0) { EXEC SQL fetch emp_cursor into :this_name, :this_salary; if (sqlca.sqlcode == 0) { skip_trailing_space(this_name); printf("%s har %d i lön.\n", this_name, this_salary); } } /* while */ EXEC SQL close emp_cursor; } /* print_employee */ /* Den här funktionen skriver ut innehållet i tabellen EMPLOYEE, * och sen får man välja vilken anställd man vill höja lönen för. */ void fix_employee(void) { EXEC SQL begin declare section; char employee_to_change[100]; EXEC SQL end declare section; print_employee(); printf("\n"); printf("Vilken anställd vill du höja lönen med 10%% för? "); smart_fgets(employee_to_change, 100, stdin); EXEC SQL update employee set salary = salary * 1.10 where name = :employee_to_change; if (sqlca.sqlcode != 0) { printf("Det finns ingen anställd med namnet %s!\n", employee_to_change); } else { printf("Ok! Ändringen utförd!\n"); print_employee(); } } /* fix_employee */ int main(void) { int yes_answer; EXEC SQL begin declare section; char database_name[100]; char part_name[20 + 1]; char supplier_name[15 + 1]; EXEC SQL end declare section; printf("\nVälkommen till ESQL-TEST-4!\n\n"); printf("Vad heter din demo-databas? "); smart_fgets(database_name, 100, stdin); EXEC SQL connect :database_name; do { fix_employee(); printf("\n"); yes_answer = ask_yes_or_no("Vill du göra fler ändringar?"); if (yes_answer) printf("Jaha. Då kör vi vidare!\n"); else printf("Nähä. Tack och adjö.\n"); } while (yes_answer != 0); printf("\n"); if (ask_yes_or_no("Är ändringarna ok?")) { printf("Ok. Då gör vi en COMMIT nu!\n"); EXEC SQL commit; /* Görs annars automatiskt i EXEC SQL disconnect; */ } else { printf("Nähä. I så fall gör vi en ROLLBACK nu.\n"); EXEC SQL rollback; } print_employee(); EXEC SQL disconnect; printf("\n"); printf("Slut i rutan.\n"); return 0; } /* main */