pgtclcmds.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,082 行 · 第 1/4 页
C
2,082 行
-getTuple tupleNumber returns the values of the tuple in a list -tupleArray tupleNumber arrayName stores the values of the tuple in array arrayName, indexed by the attributes returned -attributes returns a list of the name/type pairs of the tuple attributes -lAttributes returns a list of the {name type len} entries of the tuple attributes -clear clear the result buffer. Do not reuse after this **********************************/intPg_result(ClientData cData, Tcl_Interp *interp, int argc, CONST84 char *argv[]){ PGresult *result; const char *opt; int i; int tupno; CONST84 char *arrVar; char nameBuffer[256]; const char *appendstr; if (argc < 3 || argc > 5) { Tcl_AppendResult(interp, "Wrong # of arguments\n", 0); goto Pg_result_errReturn; /* append help info */ } result = PgGetResultId(interp, argv[1]); if (result == (PGresult *) NULL) { Tcl_AppendResult(interp, "\n", argv[1], " is not a valid query result", 0); return TCL_ERROR; } opt = argv[2]; if (strcmp(opt, "-status") == 0) { Tcl_AppendResult(interp, PQresStatus(PQresultStatus(result)), 0); return TCL_OK; } else if (strcmp(opt, "-error") == 0) { Tcl_SetResult(interp, (char *) PQresultErrorMessage(result), TCL_STATIC); return TCL_OK; } else if (strcmp(opt, "-conn") == 0) return PgGetConnByResultId(interp, argv[1]); else if (strcmp(opt, "-oid") == 0) { sprintf(interp->result, "%u", PQoidValue(result)); return TCL_OK; } else if (strcmp(opt, "-clear") == 0) { PgDelResultId(interp, argv[1]); PQclear(result); return TCL_OK; } else if (strcmp(opt, "-numTuples") == 0) { sprintf(interp->result, "%d", PQntuples(result)); return TCL_OK; } else if (strcmp(opt, "-cmdTuples") == 0) { sprintf(interp->result, "%s", PQcmdTuples(result)); return TCL_OK; } else if (strcmp(opt, "-numAttrs") == 0) { sprintf(interp->result, "%d", PQnfields(result)); return TCL_OK; } else if (strcmp(opt, "-assign") == 0) { if (argc != 4) { Tcl_AppendResult(interp, "-assign option must be followed by a variable name", 0); return TCL_ERROR; } arrVar = argv[3]; /* * this assignment assigns the table of result tuples into a giant * array with the name given in the argument. The indices of the * array are of the form (tupno,attrName). Note we expect field * names not to exceed a few dozen characters, so truncating to * prevent buffer overflow shouldn't be a problem. */ for (tupno = 0; tupno < PQntuples(result); tupno++) { for (i = 0; i < PQnfields(result); i++) { sprintf(nameBuffer, "%d,%.200s", tupno, PQfname(result, i)); if (Tcl_SetVar2(interp, arrVar, nameBuffer,#ifdef TCL_ARRAYS tcl_value(PQgetvalue(result, tupno, i)),#else PQgetvalue(result, tupno, i),#endif TCL_LEAVE_ERR_MSG) == NULL) return TCL_ERROR; } } Tcl_AppendResult(interp, arrVar, 0); return TCL_OK; } else if (strcmp(opt, "-assignbyidx") == 0) { if (argc != 4 && argc != 5) { Tcl_AppendResult(interp, "-assignbyidx option requires an array name and optionally an append string", 0); return TCL_ERROR; } arrVar = argv[3]; appendstr = (argc == 5) ? (const char *) argv[4] : ""; /* * this assignment assigns the table of result tuples into a giant * array with the name given in the argument. The indices of the * array are of the form (field0Value,attrNameappendstr). Here, we * still assume PQfname won't exceed 200 characters, but we dare * not make the same assumption about the data in field 0 nor the * append string. */ for (tupno = 0; tupno < PQntuples(result); tupno++) { const char *field0 =#ifdef TCL_ARRAYS tcl_value(PQgetvalue(result, tupno, 0));#else PQgetvalue(result, tupno, 0);#endif char *workspace = malloc(strlen(field0) + strlen(appendstr) + 210); for (i = 1; i < PQnfields(result); i++) { sprintf(workspace, "%s,%.200s%s", field0, PQfname(result, i), appendstr); if (Tcl_SetVar2(interp, arrVar, workspace,#ifdef TCL_ARRAYS tcl_value(PQgetvalue(result, tupno, i)),#else PQgetvalue(result, tupno, i),#endif TCL_LEAVE_ERR_MSG) == NULL) { free(workspace); return TCL_ERROR; } } free(workspace); } Tcl_AppendResult(interp, arrVar, 0); return TCL_OK; } else if (strcmp(opt, "-getTuple") == 0) { if (argc != 4) { Tcl_AppendResult(interp, "-getTuple option must be followed by a tuple number", 0); return TCL_ERROR; } tupno = atoi(argv[3]); if (tupno < 0 || tupno >= PQntuples(result)) { Tcl_AppendResult(interp, "argument to getTuple cannot exceed number of tuples - 1", 0); return TCL_ERROR; }#ifdef TCL_ARRAYS for (i = 0; i < PQnfields(result); i++) Tcl_AppendElement(interp, tcl_value(PQgetvalue(result, tupno, i)));#else for (i = 0; i < PQnfields(result); i++) Tcl_AppendElement(interp, PQgetvalue(result, tupno, i));#endif return TCL_OK; } else if (strcmp(opt, "-tupleArray") == 0) { if (argc != 5) { Tcl_AppendResult(interp, "-tupleArray option must be followed by a tuple number and array name", 0); return TCL_ERROR; } tupno = atoi(argv[3]); if (tupno < 0 || tupno >= PQntuples(result)) { Tcl_AppendResult(interp, "argument to tupleArray cannot exceed number of tuples - 1", 0); return TCL_ERROR; } for (i = 0; i < PQnfields(result); i++) { if (Tcl_SetVar2(interp, argv[4], PQfname(result, i),#ifdef TCL_ARRAYS tcl_value(PQgetvalue(result, tupno, i)),#else PQgetvalue(result, tupno, i),#endif TCL_LEAVE_ERR_MSG) == NULL) return TCL_ERROR; } return TCL_OK; } else if (strcmp(opt, "-attributes") == 0) { for (i = 0; i < PQnfields(result); i++) Tcl_AppendElement(interp, PQfname(result, i)); return TCL_OK; } else if (strcmp(opt, "-lAttributes") == 0) { for (i = 0; i < PQnfields(result); i++) { /* start a sublist */ if (i > 0) Tcl_AppendResult(interp, " {", 0); else Tcl_AppendResult(interp, "{", 0); Tcl_AppendElement(interp, PQfname(result, i)); sprintf(nameBuffer, "%ld", (long) PQftype(result, i)); Tcl_AppendElement(interp, nameBuffer); sprintf(nameBuffer, "%ld", (long) PQfsize(result, i)); Tcl_AppendElement(interp, nameBuffer); /* end the sublist */ Tcl_AppendResult(interp, "}", 0); } return TCL_OK; } else { Tcl_AppendResult(interp, "Invalid option\n", 0); goto Pg_result_errReturn; /* append help info */ }Pg_result_errReturn: Tcl_AppendResult(interp, "pg_result result ?option? where option is\n", "\t-status\n", "\t-error\n", "\t-conn\n", "\t-oid\n", "\t-numTuples\n", "\t-cmdTuples\n", "\t-numAttrs\n" "\t-assign arrayVarName\n", "\t-assignbyidx arrayVarName ?appendstr?\n", "\t-getTuple tupleNumber\n", "\t-tupleArray tupleNumber arrayVarName\n", "\t-attributes\n" "\t-lAttributes\n" "\t-clear\n", (char *) 0); return TCL_ERROR;}/********************************** * pg_execute send a query string to the backend connection and process the result syntax: pg_execute ?-array name? ?-oid varname? connection query ?loop_body? the return result is the number of tuples processed. If the query returns tuples (i.e. a SELECT statement), the result is placed into variables **********************************/intPg_execute(ClientData cData, Tcl_Interp *interp, int argc, CONST84 char *argv[]){ Pg_ConnectionId *connid; PGconn *conn; PGresult *result; int i; int tupno; int ntup; int loop_rc; CONST84 char *oid_varname = NULL; CONST84 char *array_varname = NULL; char buf[64]; char *usage = "Wrong # of arguments\n" "pg_execute ?-array arrayname? ?-oid varname? " "connection queryString ?loop_body?"; /* * First we parse the options */ i = 1; while (i < argc) { if (argv[i][0] != '-') break; if (strcmp(argv[i], "-array") == 0) { /* * The rows should appear in an array vs. to single variables */ i++; if (i == argc) { Tcl_SetResult(interp, usage, TCL_VOLATILE); return TCL_ERROR; } array_varname = argv[i++]; continue; } if (strcmp(argv[i], "-oid") == 0) { /* * We should place PQoidValue() somewhere */ i++; if (i == argc) { Tcl_SetResult(interp, usage, TCL_VOLATILE); return TCL_ERROR; } oid_varname = argv[i++]; continue; } Tcl_AppendResult(interp, "Unknown option '", argv[i], "'", NULL); return TCL_ERROR; } /* * Check that after option parsing at least 'connection' and 'query' * are left */ if (argc - i < 2) { Tcl_SetResult(interp, usage, TCL_VOLATILE); return TCL_ERROR; } /* * Get the connection and make sure no COPY command is pending */ conn = PgGetConnectionId(interp, argv[i++], &connid); if (conn == (PGconn *) NULL) return TCL_ERROR; if (connid->res_copyStatus != RES_COPY_NONE) { Tcl_SetResult(interp, "Attempt to query while COPY in progress", TCL_STATIC); return TCL_ERROR; } /* * Execute the query */ result = PQexec(conn, argv[i++]); /* * Transfer any notify events from libpq to Tcl event queue. */ PgNotifyTransferEvents(connid); /* * Check for errors */ if (result == NULL) { Tcl_SetResult(interp, PQerrorMessage(conn), TCL_VOLATILE); return TCL_ERROR; } /* * Set the oid variable to the returned oid of an INSERT statement if * requested (or 0 if it wasn't an INSERT) */ if (oid_varname != NULL) { char oid_buf[32]; sprintf(oid_buf, "%u", PQoidValue(result)); if (Tcl_SetVar(interp, oid_varname, oid_buf, TCL_LEAVE_ERR_MSG) == NULL) { PQclear(result); return TCL_ERROR; } } /* * Decide how to go on based on the result status */ switch (PQresultStatus(result)) { case PGRES_TUPLES_OK: /* fall through if we have tuples */ break; case PGRES_EMPTY_QUERY: case PGRES_COMMAND_OK: case PGRES_COPY_IN: case PGRES_COPY_OUT: /* tell the number of affected tuples for non-SELECT queries */ Tcl_SetResult(interp, PQcmdTuples(result), TCL_VOLATILE); PQclear(result); return TCL_OK; default: /* anything else must be an error */ Tcl_ResetResult(interp); Tcl_AppendElement(interp, PQresStatus(PQresultStatus(result))); Tcl_AppendElement(interp, PQresultErrorMessage(result)); PQclear(result); return TCL_ERROR; } /* * We reach here only for queries that returned tuples */ if (i == argc) { /* * We don't have a loop body. If we have at least one result row, * we set all the variables to the first one and return. */ if (PQntuples(result) > 0) { if (execute_put_values(interp, array_varname, result, 0) != TCL_OK) { PQclear(result); return TCL_ERROR; } } sprintf(buf, "%d", PQntuples(result)); Tcl_SetResult(interp, buf, TCL_VOLATILE); PQclear(result); return TCL_OK; } /* * We have a loop body. For each row in the result set put the values * into the Tcl variables and execute the body. */ ntup = PQntuples(result); for (tupno = 0; tupno < ntup; tupno++) { if (execute_put_values(interp, array_varname, result, tupno) != TCL_OK) { PQclear(result); return TCL_ERROR; } loop_rc = Tcl_Eval(interp, argv[i]); /* The returncode of the loop body controls the loop execution */ if (loop_rc == TCL_OK || loop_rc == TCL_CONTINUE) /* OK or CONTINUE means start next loop invocation */ continue; if (loop_rc == TCL_RETURN) { /* RETURN means hand up the given interpreter result */ PQclear(result); return TCL_RETURN; } if (loop_rc == TCL_BREAK) /* BREAK means leave the loop */ break; PQclear(result); return TCL_ERROR; } /* * At the end of the loop we put the number of rows we got into the * interpreter result and clear the result set. */ sprintf(buf, "%d", ntup); Tcl_SetResult(interp, buf, TCL_VOLATILE); PQclear(result); return TCL_OK;}/********************************** * execute_put_values Put the values of one tuple into Tcl variables named like the column names, or into an array indexed by the column names. **********************************/static intexecute_put_values(Tcl_Interp *interp, CONST84 char *array_varname, PGresult *result, int tupno){ int i; int n; char *fname; char *value; /* * For each column get the column name and value and put it into a Tcl * variable (either scalar or array item) */ n = PQnfields(result); for (i = 0; i < n; i++) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?