/***************************************************************************** * * Name: lob2file.c * * Author: Bill Bailey * * Created: 6/14/99 * * Description: This C function is intended for use as an external procedure * which unloads the contents of a BLOB into a binary OS file. * *****************************************************************************/ #include #include #include #include #include #define DEFAULT_CHUNK_SIZE 1024 static int logging; static char logfile[512]; static FILE *logfilep = NULL; int lob2file ( OCILobLocator *a_lob, /* the LOB */ short lbind, /* LOB indicator */ char *path, /* file to write */ short pind, /* file indicator */ int plen, /* filename length */ char *lpath, /* logfile name */ short lpind, /* logfile indicator */ int lplen, /* logfile name length */ int logit, /* logging enabled? */ OCIExtProcContext *ctxt /* OCI Context */ ) { sword errnum = 0; OCIEnv *envhp = NULL; OCISvcCtx *svchp = NULL; OCIError *errhp = NULL; char lobfile[512]; FILE *lobfilep = NULL; /* * If required, open the log file for writing * Use the user provided logfile name if possible * Otherwise, default the logfile to /tmp/lob2file.log */ logging = logit; if (logging) { if (lpind == -1 || lplen == 0 || lplen >= 512) { strcpy(logfile, "/tmp/lob2file.log"); } else { strncpy(logfile, lpath, lplen); logfile[lplen] = '\0'; } logfilep = fopen(logfile, "w"); if (logfilep == NULL) { if ((logfilep = fopen("/tmp/lob2file.log", "w")) != NULL) { fprintf(logfilep, "Error: Unable to open logfile %s\n", logfile); fprintf(logfilep, "Error: errno = %d\n", errno); } } } /* * Retrieve the environment, service context, and error handles */ if ((errnum = OCIExtProcGetEnv(ctxt, &envhp, &svchp, &errhp)) != OCIEXTPROC_SUCCESS) { if (logging && logfilep != NULL) { fprintf(logfilep, "Error: Call to OCIExtProcGetEnv failed\n"); fprintf(logfilep, "Error: OCIExtProcGetEnv returned %d\n", errnum); fclose(logfilep); return -1; } } /* * Verify that the user has provided a name for the output file */ if (pind == -1 || plen == 0) { char *errmsg = "Pathname is null or empty string"; if (logging && logfilep != NULL) { fprintf(logfilep, "Error: %s\n", errmsg); fclose(logfilep); } errnum = 20001; OCIExtProcRaiseExcpWithMsg(ctxt, errnum, (text *)errmsg, strlen(errmsg)); return -1; } else /* Use the provided name */ { strncpy(lobfile, path, plen); lobfile[plen] = '\0'; } /* * Verify that the user has provided a valid LOB locator */ if (lbind == -1) { char *errmsg = "LOB locator is null"; if (logging && logfilep != NULL) { fprintf(logfilep, "Error: %s\n", errmsg); fclose(logfilep); } errnum = 20002; OCIExtProcRaiseExcpWithMsg(ctxt, errnum, (text *)errmsg, strlen(errmsg)); return -1; } if (logging && logfilep != NULL) fprintf(logfilep, "Opening OS file in write mode\n"); /* * Open the output file for writing */ if ((lobfilep = fopen(lobfile, "wb")) != NULL) { dvoid *chunk; ub4 cksz = 0, totsz = 0; if (logging && logfilep != NULL) fprintf(logfilep, "Getting total size for LOB\n"); if (checkerr(ctxt, errhp, OCILobGetLength(svchp, errhp, a_lob, &totsz)) != 0) return -1; /* * For 8.0.X the OCILogGetChunkSize will not have been called. * IN this case, reset the chunk size to 1K. */ if (cksz == 0) cksz = DEFAULT_CHUNK_SIZE; if (logging && logfilep != NULL) fprintf(logfilep, "Allocating %d bytes of memory for LOB chunks\n", (int) cksz ); /* * Dynamically allocate enough memory to hold a single chunk */ if ((chunk = OCIExtProcAllocCallMemory(ctxt, (size_t) cksz)) != NULL) { int cnt = 1; ub4 amt = cksz, offset = 1; /* * Read data from the LOB and write it to the file while * more data remains. */ while (offset < (int)totsz) { if (logging && logfilep != NULL) fprintf(logfilep, "Reading chunk %d starting at %d for max %d bytes\n", cnt, (int) offset, (int) amt); errnum = OCILobRead(svchp, errhp, a_lob, &amt, offset, chunk, cksz, (dvoid *) 0, (sb4 (*)(dvoid *, dvoid *, ub4, ub1)) 0, (ub2) 0, (ub1)SQLCS_IMPLICIT); if (checkerr(ctxt, errhp, errnum) != 0) return -1; if (logging && logfilep != NULL) fprintf(logfilep, "Successfully read chunk containing %d bytes\n", (int) amt); if (logging && logfilep != NULL) fprintf(logfilep, "Writing %d bytes of chunk %d to file %s\n", (int) amt, cnt, lobfile); if (fwrite((void *)chunk, (size_t)1, (size_t)amt, lobfilep) == amt) { if (logging && logfilep != NULL) fprintf(logfilep, "Successfully wrote %d bytes to file %s\n", (int) amt, lobfile); } else { char *errmsg = "Write to OS file failed"; if (logging && logfilep != NULL) { fprintf(logfilep, "Error: %s\n", errmsg); fprintf(logfilep, "Error: errno = %d\n", errno); } errnum = 20003; OCIExtProcRaiseExcpWithMsg(ctxt, errnum, (text *)errmsg, strlen(errmsg)); return -1; } cnt++; offset += amt; } if (logfilep != NULL) fclose(logfilep); fclose(lobfilep); return 0; } else { if (logging && logfilep != NULL) { fprintf(logfilep, "Error: Unable to allocate memory\n"); fclose(logfilep); } return -1; } } else { char *errmsg = "Unable to open file"; if (logging && logfilep != NULL) { fprintf(logfilep, "Error: %s %s\n", errmsg, lobfile); fprintf(logfilep, "Error: errno = %d\n", errno); fclose(logfilep); } errnum = 20003; OCIExtProcRaiseExcpWithMsg(ctxt, errnum, (text *)errmsg, strlen(errmsg)); return -1; } } int checkerr(OCIExtProcContext *ctxt, OCIError *errhp, sword status) { sword errnum = 0; text errbuf[512]; switch (status) { case OCI_SUCCESS_WITH_INFO: errnum = 20004; strcpy((char *)errbuf, "Error: OCI_SUCCESS_WITH_INFO"); break; case OCI_NO_DATA: errnum = 20005; strcpy((char *)errbuf, "Error: OCI_NO_DATA"); break; case OCI_NEED_DATA: errnum = 20006; strcpy((char *)errbuf, "Error: OCI_NEED_DATA"); break; case OCI_INVALID_HANDLE: errnum = 20007; strcpy((char *)errbuf, "Error: OCI_INVALID_HANDLE"); break; case OCI_STILL_EXECUTING: errnum = 20008; strcpy((char *)errbuf, "Error: OCI_STILL_EXECUTING"); break; case OCI_CONTINUE: errnum = 20009; strcpy((char *)errbuf, "Error: OCI_CONTINUE"); break; case OCI_ERROR: (void)OCIErrorGet((dvoid *) errhp, (ub4) 1, (text *) NULL, (sb4 *) &errnum, (text *) errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); break; default: break; } if (errnum != 0) { if (logging && logfilep != NULL) { fprintf(logfilep, "Error: %d %s\n", errnum, errbuf); fclose(logfilep); } (void)OCIExtProcRaiseExcpWithMsg(ctxt, errnum, errbuf, strlen(errbuf)); } return errnum; }