📄 pgtclcmds.c
字号:
/*------------------------------------------------------------------------- * * pgtclCmds.c * C functions which implement pg_* tcl commands * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/interfaces/libpgtcl/pgtclCmds.c,v 1.44 1999/05/25 22:43:43 momjian Exp $ * *------------------------------------------------------------------------- */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "postgres.h"#include "pgtclCmds.h"#include "pgtclId.h"#include "libpq/libpq-fs.h" /* large-object interface */#ifdef TCL_ARRAYS#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))#define DIGIT(c) ((c) - '0')/* * translate_escape() * * This function performs in-place translation of a single C-style * escape sequence pointed by p. Curly braces { } and double-quote * are left escaped if they appear inside an array. * The value returned is the pointer to the last character (the one * just before the rest of the buffer). */static inline char *translate_escape(char *p, int isArray){ char c, *q, *s;#ifdef TCL_ARRAYS_DEBUG_ESCAPE printf(" escape = '%s'\n", p);#endif /* Address of the first character after the escape sequence */ s = p + 2; switch (c = *(p + 1)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c = DIGIT(c); if (ISOCTAL(*s)) c = (c << 3) + DIGIT(*s++); if (ISOCTAL(*s)) c = (c << 3) + DIGIT(*s++); *p = c; break; case 'b': *p = '\b'; break; case 'f': *p = '\f'; break; case 'n': *p = '\n'; break; case 'r': *p = '\r'; break; case 't': *p = '\t'; break; case 'v': *p = '\v'; break; case '\\': case '{': case '}': case '"': /* * Backslahes, curly braces and double-quotes are left escaped * if they appear inside an array. They will be unescaped by * Tcl in Tcl_AppendElement. The buffer position is advanced * by 1 so that the this character is not processed again by * the caller. */ if (isArray) return p + 1; else *p = c; break; case '\0': /* * This means a backslash at the end of the string. It should * never happen but in that case replace the \ with a \0 but * don't shift the rest of the buffer so that the caller can * see the end of the string and terminate. */ *p = c; return p; break; default: /* * Default case, store the escaped character over the * backslash and shift the buffer over itself. */ *p = c; } /* Shift the rest of the buffer over itself after the current char */ q = p + 1; for (; *s;) *q++ = *s++; *q = '\0';#ifdef TCL_ARRAYS_DEBUG_ESCAPE printf(" after = '%s'\n", p);#endif return p;}/* * tcl_value() * * This function does in-line conversion of a value returned by libpq * into a tcl string or into a tcl list if the value looks like the * representation of a postgres array. */static char *tcl_value(char *value){ int literal, last; char *p; if (!value) return (char *) NULL;#ifdef TCL_ARRAYS_DEBUG printf("pq_value = '%s'\n", value);#endif last = strlen(value) - 1; if ((last >= 1) && (value[0] == '{') && (value[last] == '}')) { /* Looks like an array, replace ',' with spaces */ /* Remove the outer pair of { }, the last first! */ value[last] = '\0'; value++; literal = 0; for (p = value; *p; p++) { if (!literal) { /* We are at the list level, look for ',' and '"' */ switch (*p) { case '"': /* beginning of literal */ literal = 1; break; case ',': /* replace the ',' with space */ *p = ' '; break; } } else { /* We are inside a C string */ switch (*p) { case '"': /* end of literal */ literal = 0; break; case '\\': /* * escape sequence, translate it */ p = translate_escape(p, 1); break; } } if (!*p) break; } } else { /* Looks like a normal scalar value */ for (p = value; *p; p++) { if (*p == '\\') { /* * escape sequence, translate it */ p = translate_escape(p, 0); } if (!*p) break; } }#ifdef TCL_ARRAYS_DEBUG printf("tcl_value = '%s'\n\n", value);#endif return value;}#endif /* TCL_ARRAYS *//********************************** * pg_conndefaults syntax: pg_conndefaults the return result is a list describing the possible options and their current default values for a call to pg_connect with the new -conninfo syntax. Each entry in the list is a sublist of the format: {optname label dispchar dispsize value} **********************************/intPg_conndefaults(ClientData cData, Tcl_Interp *interp, int argc, char **argv){ PQconninfoOption *option; Tcl_DString result; char ibuf[32]; Tcl_DStringInit(&result); for (option = PQconndefaults(); option->keyword != NULL; option++) { char *val = option->val ? option->val : ""; sprintf(ibuf, "%d", option->dispsize); Tcl_DStringStartSublist(&result); Tcl_DStringAppendElement(&result, option->keyword); Tcl_DStringAppendElement(&result, option->label); Tcl_DStringAppendElement(&result, option->dispchar); Tcl_DStringAppendElement(&result, ibuf); Tcl_DStringAppendElement(&result, val); Tcl_DStringEndSublist(&result); } Tcl_DStringResult(interp, &result); return TCL_OK;}/********************************** * pg_connect make a connection to a backend. syntax: pg_connect dbName [-host hostName] [-port portNumber] [-tty pqtty]] the return result is either an error message or a handle for a database connection. Handles start with the prefix "pgp" **********************************/intPg_connect(ClientData cData, Tcl_Interp *interp, int argc, char *argv[]){ char *pghost = NULL; char *pgtty = NULL; char *pgport = NULL; char *pgoptions = NULL; char *dbName; int i; PGconn *conn; if (argc == 1) { Tcl_AppendResult(interp, "pg_connect: database name missing\n", 0); Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]\n", 0); Tcl_AppendResult(interp, "pg_connect -conninfo <conninfo-string>", 0); return TCL_ERROR; } if (!strcmp("-conninfo", argv[1])) { /* * Establish a connection using the new PQconnectdb() interface */ if (argc != 3) { Tcl_AppendResult(interp, "pg_connect: syntax error\n", 0); Tcl_AppendResult(interp, "pg_connect -conninfo <conninfo-string>", 0); return TCL_ERROR; } conn = PQconnectdb(argv[2]); } else { /* * Establish a connection using the old PQsetdb() interface */ if (argc > 2) { /* parse for pg environment settings */ i = 2; while (i + 1 < argc) { if (strcmp(argv[i], "-host") == 0) { pghost = argv[i + 1]; i += 2; } else if (strcmp(argv[i], "-port") == 0) { pgport = argv[i + 1]; i += 2; } else if (strcmp(argv[i], "-tty") == 0) { pgtty = argv[i + 1]; i += 2; } else if (strcmp(argv[i], "-options") == 0) { pgoptions = argv[i + 1]; i += 2; } else { Tcl_AppendResult(interp, "Bad option to pg_connect : \n", argv[i], 0); Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]", 0); return TCL_ERROR; } } /* while */ if ((i % 2 != 0) || i != argc) { Tcl_AppendResult(interp, "wrong # of arguments to pg_connect\n", argv[i], 0); Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]", 0); return TCL_ERROR; } } dbName = argv[1]; conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); } if (PQstatus(conn) == CONNECTION_OK) { PgSetConnectionId(interp, conn); return TCL_OK; } else { Tcl_AppendResult(interp, "Connection to database failed\n", PQerrorMessage(conn), 0); PQfinish(conn); return TCL_ERROR; }}/********************************** * pg_disconnect close a backend connection syntax: pg_disconnect connection The argument passed in must be a connection pointer. **********************************/intPg_disconnect(ClientData cData, Tcl_Interp *interp, int argc, char *argv[]){ Tcl_Channel conn_chan; if (argc != 2) { Tcl_AppendResult(interp, "Wrong # of arguments\n", "pg_disconnect connection", 0); return TCL_ERROR; } conn_chan = Tcl_GetChannel(interp, argv[1], 0); if (conn_chan == NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, argv[1], " is not a valid connection\n", 0); return TCL_ERROR; } return Tcl_UnregisterChannel(interp, conn_chan);}/********************************** * pg_exec send a query string to the backend connection syntax: pg_exec connection query the return result is either an error message or a handle for a query result. Handles start with the prefix "pgp" **********************************/intPg_exec(ClientData cData, Tcl_Interp *interp, int argc, char *argv[]){ Pg_ConnectionId *connid; PGconn *conn; PGresult *result; if (argc != 3) { Tcl_AppendResult(interp, "Wrong # of arguments\n", "pg_exec connection queryString", 0); return TCL_ERROR; } conn = PgGetConnectionId(interp, argv[1], &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; } result = PQexec(conn, argv[2]); /* Transfer any notify events from libpq to Tcl event queue. */ PgNotifyTransferEvents(connid); if (result) { int rId = PgSetResultId(interp, argv[1], result); ExecStatusType rStat = PQresultStatus(result); if (rStat == PGRES_COPY_IN || rStat == PGRES_COPY_OUT) { connid->res_copyStatus = RES_COPY_INPROGRESS; connid->res_copy = rId; } return TCL_OK; } else { /* error occurred during the query */ Tcl_SetResult(interp, PQerrorMessage(conn), TCL_VOLATILE); return TCL_ERROR; }}/********************************** * pg_result get information about the results of a query syntax: pg_result result ?option? the options are: -status the status of the result -error the error message, if the status indicates error; otherwise an empty string -conn the connection that produced the result -oid if command was an INSERT, the OID of the inserted tuple -numTuples the number of tuples in the query -numAttrs returns the number of attributes returned by the query -assign arrayName assign the results to an array, using subscripts of the form (tupno,attributeName) -assignbyidx arrayName ?appendstr? assign the results to an array using the first field's value as a key. All but the first field of each tuple are stored, using subscripts of the form (field0value,attributeNameappendstr) -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, char *argv[]){ PGresult *result; char *opt; int i; int tupno;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -