📄 gqlplus.c
字号:
/* Check if file 'fptr' contains an editor definition line.*/static char **file_editor(FILE *fptr, char *line){ char **editor = (char **) 0; while (fgets(line, MAX_LINE_LENGTH, fptr) && (editor == (char **) 0)) if ((line[0] != '#') && strstr(line, DEFINE_CMD) && (strstr(line, EDITOR))) editor = set_editor(line); fclose(fptr); return editor;}/* Extract EDITOR definition from glogin.sql and login.sql files. sqlplus takes settings from glogin.sql in ${ORACLE_HOME}/sqlplus/admin directory first. Then it looks for login.sql file in the local directory, followed by directories in ${SQLPATH}. Note that as soon as login.sql is found in any of these directories, the search stops.*/static char **file_set_editor(char *line){ int found; int cntr; char *path; char **editor = (char **) 0; char **sqlpath; char *oracle_home; FILE *fptr; path = malloc(1024); /* Check local directory first. */ found = 0; strcpy(path, "login.sql"); fptr = fopen(path, "r"); if (fptr) { found = 1; editor = file_editor(fptr, line); } /* If login.sql is not found in the local directory, check SQLPATH directories. */ sqlpath = str_tokenize(getenv("SQLPATH"), ":"); if (sqlpath) { cntr = 0; while (!found && sqlpath[cntr]) { sprintf(path, "%s/login.sql", sqlpath[cntr]); cntr++; fptr = fopen(path, "r"); if (fptr) { found = 1; editor = file_editor(fptr, line); } } str_free(sqlpath); } if (!found) { /* login.sql not found. Check ${ORACLE_HOME}/sqlplus/admin/gqlplus.sql. */ oracle_home = getenv("ORACLE_HOME"); if (oracle_home) { sprintf(path, "%s/sqlplus/admin/glogin.sql", oracle_home); fptr = fopen(path, "r"); if (fptr) { found = 1; editor = file_editor(fptr, line); } } } free(path); return editor;}/* Send 'xtr' to sqlplus using 'i' command.*/ static void insert_line(int fdin, int fdout, char *xtr, char *ccmd, char *line){ char *str; char *prompt; if (xtr && *xtr) { sprintf(ccmd, "i %s\n", xtr); write(fdout, ccmd, strlen(ccmd)); prompt = get_sqlplus(fdin, line, &str); free(prompt); free(str); }}static void free_nta(char **nta){ int i; if (nta != (char **) 0) { i = 0; while (nta[i] != (char *) 0) free(nta[i++]); free(nta); }}/* Implement 'PAUSE ON' mode. Requires special processing, since during the dialogue with sqlplus no prompt is returned.*/static void pause_cmd(int fdin, int fdout, char *line, char *sql_prompt, int first_flag){ int result; int done; int dn; int llen; int capacity; int flags; int process_response; int len; char *lx; char *response; char *sp; char *prompt; char buffer[BUF_LEN]; /* Get sqlplus output without blocking. */ flags = fcntl(fdin, F_GETFL, 0); fcntl(fdin, F_SETFL, (flags | O_NDELAY)); /* Send the command to sqlplus. */ write(fdout, line, strlen(line)); write(fdout, "\n", 1); if (first_flag) process_response = 1; else process_response = 0; lx = malloc((MAX_LINE_LENGTH+1)*sizeof(char)); response = malloc((INIT_LINE_LENGTH+1)*sizeof(char)); response[0] = '\0'; capacity = INIT_LINE_LENGTH; llen = 0; if (lx && response) { done = 0; while (!done) { /* Read and display response. */ dn = 0; if (process_response) while (!dn) { result = read(fdin, buffer, 1000); if (result > 0) { if (result+llen > capacity) { while (capacity <= result+llen) capacity += capacity; response = realloc(response, capacity+1); } memcpy(&response[llen], buffer, result); llen += result; response[llen] = '\0'; } /* We should get out of the loop when sqlplus finishes sending it's response. But there is really no guaranteed way to know when sqlplus is done. So the best thing we can do here is to wait for at least one character; that means sqlplus has started sending, and with the small usleep() delay below, it probably means it will be done by the time we reach the next read() above. Again, this is not foolproof, but seems to work OK. If problems are encountered, increase the usleep() interval. */ else if ((!result || ((result < 0) && (errno == EAGAIN))) && (llen > 0)) dn = 1; else if ((result < 0) && (errno != EAGAIN)) perror(NULL); usleep(1); } process_response = 1; /* Verify if the response ends in user-defined prompt or default prompt. If so, terminate. Otherwise, display it. */ if (sql_prompt) prompt = sql_prompt; else prompt = SQL_PROMPT; sp = strstr(response, prompt); if (sp && (strlen(sp) == strlen(prompt))) { done = 1; if (!first_flag) { len = sp-response; fwrite(response, sizeof(char), len, stdout); fflush(stdout); } } else { printf("%s", response); fflush(stdout); response[0] = '\0'; llen = 0; /* Get a line from keyboard and send it to sqlplus. */ fgets(lx, MAX_LINE_LENGTH, stdin); write(fdout, lx, strlen(lx)); } } } else perror(NULL); /* Reset pipe from sqlplus to O_NDELAY. */ fcntl(fdin, F_SETFL, (flags &~ O_NDELAY)); free(lx); free(response);}/* Implement sqlplus 'edit' command. The command works in two modes: first, if no 'fname' is given, it launches editing session of afiedt.buf file, and sends the edited file to to sqlplus; if fname is given, it opens it.*/static int edit(int fdin, int fdout, char *line, char **editor, char *fname){ int child_stat; int status; int i; int xc; int len; int done; pid_t pid; char *path; char *str; char *xtr; char *ptr; char *afiedt; char *prompt; char *ccmd; char *rname; char *newline; char **xrgs = (char **) 0; char **enx = (char **) 0; FILE *fptr; status = 0; str = (char *) 0; prompt = (char *) 0; rname = (char *) 0; if (fname) { /* Optionally add .sql extension to fname. */ ptr = strstr(fname, SQLEXT); if (ptr && (strlen(ptr) == strlen(SQLEXT))) rname = strdup(fname); else { rname = malloc((strlen(fname)+strlen(SQLEXT)+1)*sizeof(char)); sprintf(rname, "%s%s", fname, SQLEXT); } } else { /* Get last SQL statement from sqlplus and put it in afiedt.buf, then open it in editor. */ write(fdout, LIST_CMD, strlen(LIST_CMD)); prompt = get_sqlplus(fdin, line, &str); /* TBD: afiedt.buf filename hardcoded. */ rname = strdup(AFIEDT); } if (fname || !strstr(str, NO_LINES)) { if (!fname) fptr = fopen(rname, "w"); if (fptr || fname) { if (!fname) { /* Have to clean-up the numeric prompt (5 characters) coming back from the LIST_CMD. */ xtr = str; while ((ptr = strchr(xtr, '\n')) != (char *) 0) { len = ptr-xtr; *ptr = '\0'; fprintf(fptr, "%s\n", xtr+5); xtr += len+1; } fprintf(fptr, "/\n"); status = fclose(fptr); } if (!status) { free(str); free(prompt); path = editor[0]; xc = 0; while (editor[xc++] != (char *) 0); xrgs = calloc(xc+5, sizeof(char *)); xc = 0; xrgs[xc++] = bname(path); i = 1; while (editor[i] != (char *) 0) { if ((newline = strchr(editor[i], '\n'))) *newline = '\0'; xrgs[xc++] = strdup(editor[i]); i++; } xrgs[xc++] = strdup(rname); /* Launch emacs in a separate window. */ if (!strcmp(xrgs[0], "emacs")) if (!(xrgs[1] && !strcmp(xrgs[1], "-nw"))) { if (getenv("DISPLAY")) { xrgs[xc++] = strdup("-d"); xrgs[xc++] = strdup(getenv("DISPLAY")); } } enx = calloc(10, sizeof(char *)); xc = 0; enx[xc++] = get_env(TERM); enx[xc++] = get_env(PATH); enx[xc++] = get_env("HOME"); edit_pid = fork(); errno = 0; if (edit_pid != 0) { /* This is to restart waitpid() after SIGCHLD signal is generated (this happens when user presses Ctrl-G in Emacs). Perhaps we should just block the signal here. Also, you would expect that SA_RESTART would achieve this, but couldn't get it to work. Anyways, this is simple and it works. */ done = 0; while (done == 0) { pid = waitpid(edit_pid, &child_stat, 0); if ((pid == 0) || ((pid < 0) && (errno != EINTR))) done = 1; } } else { if (execve(path, xrgs, enx) < 0) { str = malloc(100); sprintf(str, "execve() failure; %s", path); perror(str); _exit(-1); } } edit_pid = 0; /* Restore signal handling. */ if (1 && !fname) { /* Done editing. Use 'del' and 'i' commands to send contents of afiedt.buf to sqlplus. Algorithm: delete all lines in the buffer using 'del 1 LAST' command, then send all lines from 'afiedt' to sqlplus using the 'i' command. */ afiedt = read_file(AFIEDT, line); if (afiedt != (char *) 0) { /* Remove the trailing '/'. */ len = strlen(afiedt); if (!strcmp(&(afiedt[len-3]), "\n/\n")) { len -= 3; afiedt[len] = '\0'; } write(fdout, DEL_CMD, strlen(DEL_CMD)); prompt = get_sqlplus(fdin, line, &str); free(prompt); free(str); xtr = afiedt; ccmd = malloc(MAX_LINE_LENGTH*sizeof(char)); while ((ptr = strchr(xtr, '\n')) != (char *) 0) { len = ptr-xtr; *ptr = '\0'; if (*xtr) { insert_line(fdin, fdout, xtr, ccmd, line); xtr += len+1; } } /* Last line, if not empty. */ insert_line(fdin, fdout, xtr, ccmd, line); write(fdout, LIST_CMD, strlen(LIST_CMD)); prompt = get_sqlplus(fdin, line, (char **) 0); free(prompt); free(ccmd); free(afiedt); } else status = -1; } } else fprintf(stderr, "%s", AFIEDT_ERRMSG); free_nta(enx); free_nta(xrgs); } else { fprintf(stderr, "%s", AFIEDT_ERRMSG); status = -1; } } else write(STDOUT_FILENO, NOTHING_TO_SAVE, strlen(NOTHING_TO_SAVE)); free(rname); return status;}FILE *open_log_file(){ char *fname; FILE *fptr = (FILE *) 0; fname = malloc(100*sizeof(char)); sprintf(fname, "gqlplus_%d.log", (int) getpid()); fptr = fopen(fname, "w"); free(fname); return fptr;}struct table { char *name; char *owner; char **columns;};static struct table *tables;/* Parse column names from output of 'DESCRIBE' Oracle command.*/static char **parse_columns(char *str){ int i; int j; int cflag; int capacity; int clen; int idx; char *cname; char **columns; char **tokens; capacity = INIT_NUM_COLUMNS; columns = calloc(capacity+1, sizeof(char *)); tokens = str_tokenize(str, "\n"); idx = 1; i = 0; cflag = 0; while ((cname = tokens[idx])) { idx++; if (cflag == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -