Previous PageTable Of ContentsNext Page


7. Using BLOB Data

7.1 Using the PUT BLOB Statement

7.2 Using the GET BLOB Statement

7.3 Summary of the Difference Between PUT BLOB and GET BLOB


7. Using BLOB Data

When the BLOB data size is unknown at preparation time, or your buffer is not large enough, you may want to get or put partial BLOB data each time until you can get or put the entire data.

Note: If you can allocate enough buffer size in a program, or don't care whether you can get the whole BLOB or not, then you can use the original ESQL syntax to retrieve the BLOB column, and you don't need to use the following syntax.

7.1 Using the PUT BLOB Statement

STEPS:

  1. Prepare an ESQL statement and declare the BLOB host variable as a question mark, to indicate that this BLOB host variable will be bound later.
  2. EXEC SQL PREPARE stmt_name FROM "SQL SYNTAX" | :sql_string_host_variable]; 

    Where "SQL SYNTAX" is a complete SQL syntax, which dmppcc will treat this syntax as static ESQL syntax, the syntax will be parsed and store the execution plan when preprocessing the syntax. When PREPARE syntax has :sql_string_host_variable, dmppcc will treat it as Dynamic ESQL syntax, the syntax will not be parsed until run time. Please refer to Chapter "Dynamic ESQL" for detail.

    If you want to handle BLOB with GET/PUT BLOB syntax later, you should define "?" for the BLOB host variable.

    For example, suppose we want to insert emp_pic into emp_table:

    EXEC SQL PREPARE stmt1 FROM    
        "INSERT INTO emp_table (emp_id,    emp_pic) VALUES (:emp_id, ?)"; 
  3. Execute this ESQL statement:
  4. EXEC SQL EXECUTE stmt_name; 

    For example:

    EXEC SQL EXECUTE stmt1; 
  5. Declare when to begin to put the BLOB:
  6. EXEC SQL BEGIN PUT BLOB FOR stmt_name; 

    For example:

    EXEC SQL BEGIN PUT BLOB FOR stmt1; 
  7. Define which BLOB variable to use for putting the BLOB and filling the information of the bufsize and bufptr. The order for PUT BLOB must be sequential from the first to the last unbound BLOB column.
  8. EXEC SQL PUT BLOB FOR stmt_name USING :host_var [:indicator_var] 
    /*host_var's data type must be longvarchar or longvarbinary) */ 

    For example:

    strcpy(buf, "This is a test");    
    b1.buf = buf; 
    b1.bufsize = strlen(buf); 
    EXEC SQL PUT BLOB FOR stmt1 USING :b1;
     
  9. Follow step 4 until there is no more BLOB data to put in this column.

  10. If there is more than one BLOB column to put, you must declare when to begin putting the next BLOB column, then go to step 4 above.
  11. EXEC SQL PUT NEXT BLOB FOR stmt_name; 

    For example:

    EXEC SQL PUT NEXT BLOB FOR stmt1;  
  12. If all the BLOB column has been put into the database, you must declare that the PUT BLOB operation is finished.
  13. EXEC SQL END PUT BLOB FOR stmt_name;  

    For example:

    EXEC SQL END PUT BLOB FOR stmt1;

    For example:

    /********************************************************************** 
      * Prepare an insert statement; the input BLOB columns should use a  
     * question mark to denote it.    
     *******************************************************************/    
    EXEC SQL PREPARE stmt1 FROM "insert into emp_table \ 
                 (emp_id, emp_pic, emp_memo) values (:id, ?, ?)";
    id = 1000+j;
    /**********************************************************************    
     * Execute this statement. 
     ***********************************************************************/    
    EXEC SQL execute stmt1;
    /**********************************************************************    
     * If there are 300 characters to put into emp_pic, and we want to 
     * put it 100 characters at a time.    
     **********************************************************************/    
    pic_buffer.bufsize = 100; /* max buffer size */
    /* you must allocate enough buffer as indicated in field bufsize, or  
     *point to a valid buffer pointer */    
    pic_buffer.buf = user_buf;
    /**********************************************************************    
     * Begin PUT BLOB. 
     ***********************************************************************/    
    EXEC SQL BEGIN PUT BLOB FOR stmt1;
    /**********************************************************************    
     * Loop 3 times to put data. 
     **********************************************************************/    
    for (i=0; i < 3; i++) 
       { 
        sprintf(pic_buffer.buf, "user's picture %dth's data........ ", i); 
        EXEC SQL PUT BLOB FOR stmt1 USING :pic_buffer;    
        }
    /**********************************************************************    
     * Now start to put the next BLOB column's data. 
     **********************************************************************/    
    EXEC SQL put next blob FOR stmt1;
    /**********************************************************************    
     * If there are 200 characters to put into emp_memo, and we want to 
     * put it 100 characters at a time.    
     **********************************************************************/    
    memo_buffer.bufsize = 100; /* max buffer size */ 
    /* you must allocate enough buffer as indicated in field bufsize, or  
     *point to a valid buffer pointer */    
    memo_buffer.buf = user_buf;
    /**********************************************************************    
     * loop 2 times to put data 
     **********************************************************************/    
    for (i=0; i < 2; i++) 
        { 
        sprintf(memo_buffer.buf, "user's memo %dth's data...........", i); 
        EXEC SQL PUT BLOB FOR stmt1 USING :memo_buffer;    
        }
    /*********************************************************************    
     * end PUT BLOB 
     **********************************************************************/    
    EXEC SQL END PUT BLOB FOR stmt1;

Using the GET BLOB Statement

CASE 1: Multiple-Row Data Retrieved Using Cursor

STEPS:

  1. Prepare an ESQL statement and declare the BLOB host variable as a question mark (it means this BLOB host variable is not yet bound).
  2. EXEC SQL PREPARE stmt_name FROM "SQL SYNTAX"; 

    (Unlike dynamic ESQL syntax, the SQL SYNTAX is known at preprocessing time, and must include the bound host variable name; if it's a BLOB, and you want to use the GET/PUT BLOB method, then you must define '?'.)

    For example: suppose we want to fetch emp_pic from emp_table:

    EXEC SQL PREPARE stmt1 FROM "select emp_pic from emp_table into ?"; 
  3. Declare a cursor for a prepared statement.
  4. EXEC SQL DECLARE cursor_name CURSOR FOR stmt_name; 

    For example:

    EXEC SQL DECLARE myCur CURSOR FOR stmt1; 
  5. Open the cursor.
  6. For example:

    EXEC SQL OPEN myCur; 
  7. Fetch the cursor.
  8. For example:

    EXEC SQL FETCH myCur; 
  9. Unlike PUT BLOB, you don't need to declare when to begin GET BLOB, but you must define the column number in the BLOB host variable and the available buffer size and valid buffer pointer.
  10. EXEC SQL GET BLOB COLUMN :blobcol_num FOR stmt_name USING :host_var [:indicator_var] 

    For example:

    EXEC SQL BEGIN DECLARE SECTION;    
    int nCol; 
    longvarchar b1; 
    EXEC SQL END DECLARE SECTION;
    nCol = 1; /* assign nCol as the column order in projection */ 
    b1.bufsize = 50; /* if you want to get 50 bytes at a time */ 
    b1.buf = buf; /* assign a valid buffer pointer to b1 */ 
    EXEC SQL GET BLOB COLUMN :nCol FOR stmt2 USING :b1

    Note: You can specify an indicator variable to get the remaining buffer size before getting this BLOB column..

    EXEC SQL PREPARE stmt1 FROM "select c6 from d1 into ?"; 
    EXEC SQL EXECUTE stmt1;
    /* fetch BLOB with size = 0 first, to know total size with indicator */ 
    nCol = 1; 
    b1.bufsize = 0;    
    b1.buf = wkbuf;    
    EXEC SQL GET BLOB COLUMN :nCol FOR stmt1 USING :b1 :i_b1; 
    if (SQLCODE == 0)    
        printf("left size is %d\n", i_b1);
    /* loop fetch BLOB with size = 2, and print out "last" remain size */ 
    for (i = 0; SQLCODE != SQL_NO_DATA_FOUND; i++) 
        { 
        b1.bufsize = 2; /* get 1 char plus null ptr at a time */ 
        EXEC SQL GET BLOB COLUMN :nCol FOR stmt1 USING :b1 :i_b1; 
        if (SQLCODE != SQL_NO_DATA_FOUND)    
        printf("b1 = %s, last remain size is %d\n", b1.buf, i_b1); 
        chkErr(); 
        } 

    Or you can also set bufsize = DB_ALLOCATE_MEMORY, when you want DBMaker to allocate the memory for getting this blob. DBMaker will free the allocated memory related to the blob when you call next FETCH or CLOSE CURSOR statement. Please be careful with this option, because for allocating enough memory for the blob, maybe cause "OUT OF MEMORY" problem in the system. And because after the next FETCH or CLOSE statement, the memory will be freed by the database, the pointer of blob variable will refer to an invalid address. This may cause core dumped or error executing result in your program, please do it with cautious.

  11. Continue as in the previous step, if there's more BLOB data to get.
  12. For example:

    EXEC SQL PREPARE stmt1 FROM "select c6 from d1 into ?"; 
    EXEC SQL EXECUTE stmt1;
    /* fetch BLOB with size = 0 first, to know total size with indicator */ 
    nCol = 1; 
    b1.bufsize = 0; 
    b1.buf = wkbuf; 
    EXEC SQL GET BLOB COLUMN :nCol FOR stmt1 USING :b1 :i_b1; 
    if (SQLCODE == 0) 
        printf("left size is %d\n", i_b1);
    /* loop fetch BLOB with size = 2, and print out "last" remain size */ 
    for (i = 0; SQLCODE != SQL_NO_DATA_FOUND; i++) 
        { 
        b1.bufsize = 2; /* get 1 char plus null ptr at a time */ 
        EXEC SQL GET BLOB COLUMN :nCol FOR stmt1 USING :b1 :i_b1; 
        if (SQLCODE != SQL_NO_DATA_FOUND)    
        printf("b1 = %s, last remain size is %d\n", b1.buf, i_b1);
        chkErr(); 
        } 
  13. If all data has been retrieved or you don't want to get the rest of the BLOB data, you can continue to fetch the rest of the result buffer of this cursor until no more rows are found.
  14. For example:

    #define MAX_BUF_SIZE 101
    /* Prepare a SELECT statement, the output BLOB column should use */ 
    /* a question mark to denote it. */    
    EXEC SQL PREPARE stmt1 FROM "select emp_id, emp_pic from emp_table 
                                 into :id, ?";
    /* Declare a cursor to associate it with this statement. */ 
    EXEC SQL DECLARE myCur CURSOR FOR stmt1;
    /* Open this cursor. */ 
    EXEC SQL OPEN myCur;
    /* To get one MAX_BUF_SIZE character    at a time, we must fill the  
     * following field first. */ 
    nCol = 2; /* second output column in projection.*/ 
    pic_buffer.bufsize = MAX_BUF_SIZE; /* max buffer size */
    /* You must allocate enough buffer as indicated in field bufsize, or  
       point to a valid buffer pointer. */    
    pic_buffer.buf = user_buf;
    /* loop fetch result. */ 
    while (1) 
        { 
        EXEC SQL FETCH myCur INTO :id, ?; /* fetch cursor */ 
        if (SQLCODE) 
            { 
             if (SQLWARN0 != 'W') 
                 break; 
            }
        printf("emp_id = %d\n", id);    
        printf("emp_pic = ");    
        /* loop get BLOB data until no data is found. */ 
        for (i = 0; SQLCODE != SQL_NO_DATA_FOUND; i++) 
            { 
             EXEC SQL GET BLOB COLUMN :nCol FOR stmt1    
                               USING :pic_buffer :pic_ind; 
             if (SQLCODE != SQL_NO_DATA_FOUND)    
                 { 
                 if (pic_ind == SQL_NULL_DATA)    
                     printf("(null)"); 
                 else 
                     { 
                      for(j = 0; j < MAX_BUF_SIZE-1; j++)    
                      printf("%c", pic_buffer.buf[j]);    
                     } 
                 } 
            } 
        printf("\n"); 
        }
       /* Close the cursor. */ 
       EXEC SQL CLOSE myCur;

7.3 Summary of the Difference Between PUT BLOB and GET BLOB

Because it's not necessary to GET BLOB data in sequence, we can assign which column to get and don't have to GET BLOB data from left column to right (small column numbers to large column numbers). It's also not necessary to get the entire BLOB data if you don't want to.

PUT BLOB must start from the first to the last BLOB column, and it must be indicated when to begin and when to stop. You can't put the BLOB randomly. If you did not put each BLOB column accordingly, and did not indicate when to end PUT BLOB, the BLOB column will not actually be inserted into the database. In this case, the operation will be aborted (because the operation never finished) when you disconnect or exit from the program. If you disconnect from the database, an error will show that the last statement has been canceled.

Previous PageTop Of PageTable Of ContentsNext Page

 

Copyright 2002 SYSCOM Computer Engineering Co. All rights reserved.