Embedded SQL

Embedded SQL

CHAPTER 3 Embedded SQL Oracle SQL, introduced in the previous chapter, is not a language that can be used to build sophisticated database applications, but it is a very good language for defining the structure of the database and generating ad hoc queries. However, to build applications, the power of a full-fledged high-level programming language is needed. Embedded SQL provides such an environment to develop application programs. The basic idea behind embedded SQL is to allow SQL statements in a program written in a high-level programming language such as C or C++.By embedding SQL statements in a C/C++ program, one can now write application programs in C/C++ that interact (read and write) with the database. Oracle provides a tool, called Pro*C/C++, which allows for applications to be developed in the C or C++ language with embedded SQL statements. The Pro*C/C++ preprocessor parses the embedded program and converts all SQL statements to system calls in C/C++ and produces a C/C++ program as its output. This C/C++ program can be compiled in the usual manner to produce the executable version of the application program. This chapter introduces concepts and techniques needed to write successful embedded SQL programs in Oracle using the C or C++ language. Most of the concepts are introduced using the C language. A separate section is devoted to C++ programs. 3.1 Host Variables Since SQL statements are to be embedded within the C program, there is a need for a mechanism to pass values between the C program environment and the SQL statements that communicate with the Oracle database server. Special variables, called host variables, are defined in the embedded program for this purpose. These 93 94 Embedded SQL host variables are defined between the begin declare section and end declare section directives of the preprocessor as follows: EXEC SQL begin declare section; int cno; varchar cname[31]; varchar street[31]; int zip; char phone[13]; EXEC SQL end declare section; The data types of the host variables must be compatible with the data types of the columns of the tables in the database. Figure 3.1 shows data types in C that are compatible with commonly used data types in Oracle. The char data type in Oracle is mapped to the char data type in C. The char(N) data type in Oracle is mapped to an array of characters in C. Notice that the size of the C array is one more than the size of the character string in Oracle. This is due to the fact that C character strings require an additional character to store the end-of-string character (\0). Oracle’s Pro*C preprocessor provides a varchar array data type in C that corresponds to the varchar(N) Oracle data type. Again, the size of the C varchar array is one more than the maximum size of the varchar string of Oracle. The varchar array in C is declared as varchar cname[31]; and the Pro*C preprocessor produces the following C code corresponding to the above declaration: /* varchar cname[31]; */ struct { unsigned short len; unsigned char arr[31]; } cname; Note that the varchar array variable cname has been transformed into a structure (with the same name) containing two fields: arr and len. The arr field will store the actual string and the len field will store the length of the character string. When sending a varchar value to the database, it is the responsibility of the programmer to make sure that both fields, arr and len, are assigned proper values. When receiving such a value from the database, both fields are assigned appropriate values by the system. The date data type is mapped to a fixed-length (10 characters, corresponding to the default date format in Oracle) character string in C. The 3.1 Host Variables 95 Figure 3.1 Compatible Oracle and C data types. Oracle Data Type C Data Type char char char(N) char array[N+1] varchar(N) varchar array[N+1] date char array[10] number(6) int number(10) long int number(6,2) float numeric data types are appropriately mapped to small int, int, long int, float, or double, depending on their precisions in Oracle. The host variables are used in the usual manner within C language constructs; however, when they are used in the embedded SQL statements, they must be preceded by a colon (:). Some examples of their usage are shown in the following code fragment. scanf("%d",&cno); EXEC SQL select cname into :cname from customers where cno = :cno; scanf("%d%s%s%d%s",&cno,cname.arr,street.arr,&zip,phone); cname.len = strlen(cname.arr); street.len = strlen(street.arr); EXEC SQL insert into customers values (:cno,:cname,:street,:zip,:phone); The select statement in the above example has an additional clause, the into clause, which is required in embedded SQL since the results of the SQL statements must be stored someplace. The select into statement can be used only if it is guaranteed that the query returns exactly one or zero rows. A different technique is used to process queries that return more than one row. This technique, which uses the concept of a cursor, is discussed in Section 3.5. Note that all occurrences of the host variables within the embedded SQL statements are preceded by a colon. Also, the len fields of all varchar arrays in C are set to the correct lengths before sending the host variables to the database. 96 Embedded SQL 3.2 Indicator Variables A null value in the database does not have a counterpart in the C language environ- ment. To solve the problem of communicating null values between the C program and Oracle, embedded SQL provides indicator variables, which are special integer variables used to indicate if a null value is retrieved from the database or stored in the database. Consider the orders table of the mail-order database. The following is the declaration of the relevant host and indicator variables to access the orders table. EXEC SQL begin declare section; struct { int ono; int cno; int eno; char received[12]; char shipped[12]; } order_rec; struct { short ono_ind; short cno_ind; short eno_ind; short received_ind; short shipped_ind; } order_rec_ind; int onum; EXEC SQL end declare section; The code below reads the details of a particular row from the orders table into the host variables declared above and checks to see whether the shipped column value is null.Anull value is indicated by a value of −1 for the indicator variable. The database server returns a value of 0 for the indicator variable if the column value retrieved is not null.1 scanf("%d",&onum); EXEC SQL select * into :order_rec indicator :order_rec_ind 1. The indicator variable is also used for other purposes—for example, it is used to indicate the length of a string value that was retrieved from the database and that was truncated to fit the host variable into which it was retrieved. 3.3 SQL Communications Area (sqlca) 97 from orders where ono = :onum; if (order_rec_ind.shipped_ind == -1) printf("SHIPPED is Null\n"); else printf("SHIPPED is not Null\n"); To store a null value into the database, a value of −1 should be assigned to the indicator variable and the indicator variable should be used in an update or insert statement. For example, the following code sets the shipped value for the order with order number 1021 to null. onum = 1021; order_rec_ind.shipped_ind = -1; EXEC SQL update orders set shipped = :order_rec.shipped indicator :order_rec_ind.shipped_ind where ono = :onum; Notice that the order_rec.shipped value is undefined, because it will be ignored by the database server. 3.3 SQL Communications Area (sqlca) Immediately after the Oracle database server executes an embedded SQL statement, it reports the status of the execution in a variable called sqlca, the SQL commu- nications area. This variable is a structure with several fields, the most commonly used one being sqlcode. Typical values returned in this field are shown below. sqlca.sqlcode Interpretation 0 SQL statement executed successfully > 0 No more data present or values not found < 0 Error occurred while executing SQL statement To include the sqlca definition, the following statement must appear early in the program: EXEC SQL include sqlca; Here are two code fragments that illustrate the use of sqlca.sqlcode. Error check: Consider the following code fragment, which attempts to add a new row into the customers table. 98 Embedded SQL EXEC SQL set transaction read write; EXEC SQL insert into customers values (custseq.nextval,:customer_rec.cname, :customer_rec.street,:customer_rec.zip, :customer_rec.phone); if (sqlca.sqlcode < 0) { printf("\n\nCUSTOMER (%s) DID NOT GET ADDED\n", customer_rec.cname.arr); EXEC SQL rollback work; return; } EXEC SQL commit; After starting a transaction to read and write to the database,2 this program fragment attempts to insert a new row into the customers table using the EXEC SQL insert into statement. There could be several reasons why this statement may not execute successfully, among them primary key constraint violation, data type mismatches, and wrong number of columns in the insert statement. The value of sqlca.sqlcode is checked to see if it is less than 0. If an error is indicated, a message is sent to the user and the transaction is rolled back. Otherwise, the transaction is committed and the row is successfully inserted. Not found check: Consider the following code fragment: EXEC SQL select zip, city into :zipcode_rec from zipcodes where zip = :customer_rec.zip; if (sqlca.sqlcode > 0) { zipcode_rec.zip = customer_rec.zip; printf("Zip Code does not exist; Enter City: "); scanf("%s",zipcode_rec.city.arr); zipcode_rec.city.len = strlen(zipcode_rec.city.arr); EXEC SQL set transaction read write; EXEC SQL insert into zipcodes (zip, city) values (:zipcode_rec); EXEC SQL commit; } 2.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    59 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us