From: Billy G. A. <bal...@us...> - 2001-09-24 07:10:59
|
Update of /cvsroot/pypgsql/pypgsql In directory usw-pr-cvs1:/tmp/cvs-serv22075 Modified Files: PgSQL.py libpqmodule.c pg_types.h pgconnection.c pgresult.c pgresult.h Log Message: 24SEP2001 bga Changed how strings are quoted. The Python repr() function is no longer used, which eliminated the need for pgFixEsc(). Strings are now quoted using a (C) helper function in libpq called PgQuoteString. This quoting function does not quote characters that have an ord() value > 127, which should resolve the problem with alternate encodings [Bug #455514]. This change should also fix the pgFixEsc problem [Bug #464123]. --- Added support for the PostgreSQL BYTEA type. This includes: 1. A new PgBytea class in PgSQL. 2. A (C) helper function in libpq, called PgQuoteBytea(), which will quote BYTEA strings, which can contain embedded NUL characters. 3. A (C) helper function in libpq, called PgUnQuoteBytea(), which will remove the quoting from the BYTEA string returned from PostgreSQL. Note: The PgResult.getvalue() method will call PgUnQuoteBytea() automatically for BYTEA fields. Index: PgSQL.py =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/PgSQL.py,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** PgSQL.py 2001/09/20 03:51:00 1.21 --- PgSQL.py 2001/09/24 07:10:56 1.22 *************** *** 30,33 **** --- 30,37 ---- # Date Ini Description | # --------- --- ------------------------------------------------------- | + # 24SEP2001 bga Changed the method used to quote strings. This new way | + # does not require the services of pgFixEsc, which was | + # removed from pgconnection.c. | + # --- Added support for the PostgreSQL type BYTEA. | # 19SEP2001 bga Cleaned up the logic in hadleArray(). | # --- Updated the PgSQL.__doc__ string. | *************** *** 342,346 **** # Define the object types required by the DB-API 2.0 specification. ! BINARY = DBAPITypeObject('BINARY', PG_OID, PG_BLOB) DATETIME = DBAPITypeObject('DATETIME', PG_DATE, PG_TIME, PG_TIMESTAMP, --- 346,350 ---- # Define the object types required by the DB-API 2.0 specification. ! BINARY = DBAPITypeObject('BINARY', PG_OID, PG_BLOB, PG_BYTEA) DATETIME = DBAPITypeObject('DATETIME', PG_DATE, PG_TIME, PG_TIMESTAMP, *************** *** 485,488 **** --- 489,494 ---- else: return DateTime.ISO.ParseAny(value) + elif _ftv == PG_BYTEA: + return PgBytea(value) elif _ftv == OTHER: if isinstance(value, PgOther): *************** *** 605,612 **** return str(self.value) ! # NOTE: A PgOther object will not have any special quoting done. def _quote(self): if self.value: ! return repr(self.value) return 'NULL' --- 611,672 ---- return str(self.value) ! # NOTE: A PgOther object will use the PgQuoteString() function in libpq. def _quote(self): if self.value: ! return PgQuoteString(self.value) ! return 'NULL' ! ! #-----------------------------------------------------------------------+ ! # Name: PgBytea | ! # | ! # Description: A Python wrapper class for the PostgreSQL BYTEA type. | ! # | ! # Note: A Python String is used to store the PostgreSQL type in | ! # class. | ! #-----------------------------------------------------------------------+ ! ! class PgBytea: ! def __init__(self, value): ! if type(value) != StringType: ! raise TypeError, "argument must be a string." ! ! self.value = value ! ! if hasattr(value, '__methods__'): ! for i in self.value.__methods__: ! exec 'self.%s = self.value.%s' % (i, i) ! ! # This definition of __coerce__ will cause Python to always call the ! # (existing) arithmatic operators for this class. We can the perform the ! # appropiate operation on the base type, letting it decide what to do. ! def __coerce__(self, other): ! return (self, other) ! ! # NOTE: A string is being concatenated to a PgOther, so the result type ! # is a PgOther ! def __add__(self, other): ! return PgBytea((self.value + other)) ! ! # NOTE: A PgOther is being concatenated to a string, so the result type ! # is a string. ! def __radd__(self, other): ! return (other + self.value) ! ! def __mul__(self, other): ! return PgBytea((self.value * other)) ! ! def __rmul__(self, other): ! return PgBytea((self.value * other)) ! ! def __repr__(self): ! return repr(self.value) ! ! def __str__(self): ! return str(self.value) ! ! # NOTE: A PgBytea object will use the PgQuoteBytea() function in libpq ! def _quote(self): ! if self.value: ! return PgQuoteBytea(self.value) return 'NULL' *************** *** 1354,1361 **** if type(value) == StringType: ! _s = repr(value) ! if _s[0] == '"': ! _s = (repr((value + '"'))[:-2] + "'") ! return _s if type(value) in [DateTimeType, DateTimeDeltaType]: --- 1414,1418 ---- if type(value) == StringType: ! return PgQuoteString(value) if type(value) in [DateTimeType, DateTimeDeltaType]: *************** *** 1463,1467 **** def __closeCursors(self, flag=0): ! """__closeCursors() - closes all cursors associated with this connection""" if self.__anyLeft(): if noWeakRef: --- 1520,1525 ---- def __closeCursors(self, flag=0): ! """ ! __closeCursors() - closes all cursors associated with this connection""" if self.__anyLeft(): if noWeakRef: *************** *** 1541,1544 **** --- 1599,1607 ---- if self.__closeCursors(): self.__dict__["inTransaction"] = 0 + # Until the warning framework is in place, clear out the notices + # before doing a commit. This will allow catching any noices + # generated by the commit. + while len(self.conn.notices) > 0: + _drop = self.conn.notices.pop() res = self.conn.query("COMMIT WORK") if len(self.conn.notices) > 0: *************** *** 1560,1563 **** --- 1623,1631 ---- if self.__closeCursors(): self.__dict__["inTransaction"] = 0 + # Until the warning framework is in place, clear out the notices + # before doing a rollback. This will allow catching any noices + # generated by the rollback. + while len(self.conn.notices) > 0: + _drop = self.conn.notices.pop() res = self.conn.query("ROLLBACK WORK") if len(self.conn.notices) > 0: *************** *** 1909,1913 **** if len(self.conn.notices) > 0: ! raise Warning, self.conn.notices.pop() self._rows_ = self.res.ntuples --- 1977,1983 ---- if len(self.conn.notices) > 0: ! _drop = self.conn.notices.pop() ! if _drop.find('transaction is aborted') > 0: ! raise Warning, _drop self._rows_ = self.res.ntuples *************** *** 2029,2033 **** if len(self.conn.notices) > 0: ! raise Warning, self.conn.notices.pop() if self.res.resultType == RESULT_DQL: --- 2099,2105 ---- if len(self.conn.notices) > 0: ! _drop = self.conn.notices.pop() ! if _drop.find('transaction is aborted') > 0: ! raise Warning, _drop if self.res.resultType == RESULT_DQL: *************** *** 2043,2047 **** if len(self.conn.notices) > 0: ! raise Warning, self.conn.notices.pop() def executemany(self, query, parm_sequence): --- 2115,2121 ---- if len(self.conn.notices) > 0: ! _drop = self.conn.notices.pop() ! if _drop.find('transaction is aborted') > 0: ! raise Warning, _drop def executemany(self, query, parm_sequence): *************** *** 2078,2082 **** if len(self.conn.notices) > 0: ! raise Warning, self.conn.notices.pop() return self.__fetchOneRow() --- 2152,2158 ---- if len(self.conn.notices) > 0: ! _drop = self.conn.notices.pop() ! if _drop.find('transaction is aborted') > 0: ! raise Warning, _drop return self.__fetchOneRow() *************** *** 2122,2126 **** if len(self.conn.notices) > 0: ! raise Warning, self.conn.notices.pop() return self.__fetchManyRows(sz, _list) --- 2198,2204 ---- if len(self.conn.notices) > 0: ! _drop = self.conn.notices.pop() ! if _drop.find('transaction is aborted') > 0: ! raise Warning, _drop return self.__fetchManyRows(sz, _list) *************** *** 2155,2159 **** if len(self.conn.notices) > 0: ! raise Warning, self.conn.notices.pop() return self.__fetchManyRows(self._rows_, _list) --- 2233,2239 ---- if len(self.conn.notices) > 0: ! _drop = self.conn.notices.pop() ! if _drop.find('transaction is aborted') > 0: ! raise Warning, _drop return self.__fetchManyRows(self._rows_, _list) *************** *** 2178,2182 **** self._rows_ = 0 if len(self.conn.notices) > 0: ! raise Warning, self.conn.notices.pop() self.__dict__["rowcount"] = -1 --- 2258,2264 ---- self._rows_ = 0 if len(self.conn.notices) > 0: ! _drop = self.conn.notices.pop() ! if _drop.find('transaction is aborted') > 0: ! raise Warning, _drop self.__dict__["rowcount"] = -1 Index: libpqmodule.c =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/libpqmodule.c,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** libpqmodule.c 2001/09/16 17:54:52 1.14 --- libpqmodule.c 2001/09/24 07:10:56 1.15 *************** *** 32,35 **** --- 32,40 ---- | Date Ini Description | | --------- --- ------------------------------------------------------- | + | 24SEP2001 bga Added support routines to: | + | 1. quote strings (PgQuoteString). | + | 2. quote bytea strings (PgQuoteBytea). | + | 3. un-quote bytea strings (PgUnQuoteBytea). | + | Bytea strings can have embedded NUL values. | | 14SEP2001 bga Removed code related to PostgreSQL 6.5.x. We now only | | support PostgreSQL 7.0 and later. | *************** *** 129,132 **** --- 134,401 ---- \***********************************************************************/ + #define DIG(VAL) ((VAL) + '0') + #define VAL(CH) ((CH) - '0') + + /*--------------------------------------------------------------------------*/ + + static char libPQquoteString_Doc[] = + "PgQuoteString(string) -> string\n" + " This is a helper function that will quote a Python String in a " + "manner\n that is acceptable to PostgreSQL"; + + /***********************************************************************\ + | The following routine will quote a string in a manner acceptable for | + | use in PostgreSQL. The quoting rules are: | + | | + | 1. Control characters are quoted as follows: | + | | + | Value Quoted Representation | + | ----- --------------------- | + | NUL * NOT ALLOWED * | + | BS \b | + | TAB \t | + | NL \n | + | CR \r | + | other \OOO where OOO is the octal value of the control char. | + | | + | 2. The backslash is quoted as \\. | + | | + | 3. The single quote is quoted as \'. | + | | + | 4. All other characters are unchanged. | + \***********************************************************************/ + + static PyObject *libPQquoteString(PyObject *self, PyObject *args) + { + int i, j, slen, byte; + char *sin; + char *sout; + PyObject *result; + + if (!PyArg_ParseTuple(args,"s:PgQuoteString", &sin)) + return NULL; + + slen = strlen(sin); + sout = (char *)PyMem_Malloc((4*slen)+3); // Assume every char will be quoted + if (sout == (char *)NULL) + return PyErr_NoMemory(); + + sout[0] = '\''; + + for (i = 0, j = 1; i < slen; i++) + { + switch (sin[i]) + { + case '\'': + case '\\': + sout[j++] = '\\'; + sout[j++] = sin[i]; + break; + + case '\b': + sout[j++] = '\\'; + sout[j++] = 'b'; + break; + + case '\f': + sout[j++] = '\\'; + sout[j++] = 'f'; + break; + + case '\n': + sout[j++] = '\\'; + sout[j++] = 'n'; + break; + + case '\r': + sout[j++] = '\\'; + sout[j++] = 'r'; + break; + + case '\t': + sout[j++] = '\\'; + sout[j++] = 't'; + break; + + default: + if (sin[i] < 32) + { + // escape any control character not already escaped. + byte = (unsigned char)sin[i]; + sout[j++] = '\\'; + sout[j++] = DIG((byte >> 6) & 3); + sout[j++] = DIG((byte >> 3) & 7); + sout[j++] = DIG(byte & 7); + } + else + sout[j++] = sin[i]; + } + } + + sout[j++] = '\''; + sout[j] = (char)0; + + result = Py_BuildValue("s#", sout, j); + PyMem_Free(sout); + + return result; + } + + /*--------------------------------------------------------------------------*/ + + static char libPQquoteBytea_Doc[] = + "PgQuoteString(string) -> string\n" + " This is a helper function that will quote a Python String (that can " + "contain embedded NUL bytes) in a manner\n that is acceptable to " + "PostgreSQL"; + + /***********************************************************************\ + | The following routine will quote a bytea string in a manner accept- | + | able for use in PostgreSQL. The quoting rules are: | + | | + | 1. Control characters are quoted as \OOO where OOO is the octal | + | value of the control character. | + | | + | 2. The backslash is quoted as \\\\. | + | | + | 3. The single quote is quoted as \'. | + | | + | 4. All other characters are unchanged. | + \***********************************************************************/ + + static PyObject *libPQquoteBytea(PyObject *self, PyObject *args) + { + int i, j, slen, byte; + char *sin; + char *sout; + PyObject *result; + + if (!PyArg_ParseTuple(args,"s#:PgQuoteString", &sin, &slen)) + return NULL; + + sout = (char *)PyMem_Malloc((4*slen)+3); // Assume every char will be quoted + if (sout == (char *)NULL) + return PyErr_NoMemory(); + + sout[0] = '\''; + + for (i = 0, j = 1; i < slen; i++) + { + switch (sin[i]) + { + case '\'': + sout[j++] = '\\'; + sout[j++] = sin[i]; + break; + + case '\\': + sout[j++] = sin[i]; + sout[j++] = sin[i]; + sout[j++] = sin[i]; + sout[j++] = sin[i]; + break; + + case '\0': + sout[j++] = '\\'; + sout[j++] = '\\'; + sout[j++] = '0'; + sout[j++] = '0'; + sout[j++] = '0'; + break; + + default: + if (!isprint(sin[i])) + { + // escape any control character not already escaped. + byte = (unsigned char)sin[i]; + sout[j++] = '\\'; + sout[j++] = DIG((byte >> 6) & 3); + sout[j++] = DIG((byte >> 3) & 7); + sout[j++] = DIG(byte & 7); + } + else + sout[j++] = sin[i]; + } + } + + sout[j++] = '\''; + sout[j] = (char)0; + + result = Py_BuildValue("s#", sout, j); + PyMem_Free(sout); + + return result; + } + + /*--------------------------------------------------------------------------*/ + + PyObject *unQuoteBytea(char *sin) + { + int i, j, slen, byte; + char *sout; + PyObject *result; + + slen = strlen(sin); + sout = (char *)PyMem_Malloc(slen); + if (sout == (char *)NULL) + return PyErr_NoMemory(); + + for (i = j = 0; i < slen;) + { + switch (sin[i]) + { + case '\\': + i++; + if (sin[i] == '\\') + sout[j++] = sin[i++]; + else + { + if ((!isdigit(sin[i])) || + (!isdigit(sin[i+1])) || + (!isdigit(sin[i+2]))) + goto unquote_error; + + byte = VAL(sin[i++]); + byte = (byte << 3) + VAL(sin[i++]); + sout[j++] = (byte << 3) + VAL(sin[i++]); + } + break; + + default: + sout[j++] = sin[i++]; + } + } + + sout[j] = (char)0; + + result = Py_BuildValue("s#", sout, j); + PyMem_Free(sout); + + return result; + + unquote_error: + PyMem_Free(sout); + PyErr_SetString(PyExc_ValueError, "Bad input string for type bytea"); + return (PyObject *)NULL; + } + + static char libPQunQuoteBytea_Doc[] = + "PgUnQuoteString(string) -> string\n" + " This is a helper function that will un-quote a string that is the " + "returned\n value from a bytea field. The returned Python string may " + "contain embedded\n NUL characters."; + + static PyObject *libPQunQuoteBytea(PyObject *self, PyObject *args) + { + char *sin; + + if (!PyArg_ParseTuple(args,"s:PgUnQuoteString", &sin)) + return NULL; + + return unQuoteBytea(sin); + } + + /*--------------------------------------------------------------------------*/ + static char libPQconndefaults_Doc[] = "PQconndefaults() -> [[<option info>], ...]\n" *************** *** 140,143 **** --- 409,419 ---- PyObject *list = (PyObject *)NULL, *item = (PyObject *)NULL; + if (!PyArg_ParseTuple(args, "")) + { + PyErr_SetString(PqErr_InterfaceError, + "PQconndefaults() takes no parameters"); + return NULL; + } + opt = PQconndefaults(); *************** *** 164,167 **** --- 440,445 ---- } + /*--------------------------------------------------------------------------*/ + static char libPQconnectdb_Doc[] = "PQconnectdb(conninfo) -> PgConnection\n" *************** *** 351,386 **** switch (fieldType) { case PG_BOOL: desc = "bool"; break; ! case PG_CHAR: desc = "char"; break; case PG_BPCHAR: desc = "char"; break; ! case PG_NAME: desc = "name"; break; ! case PG_INT8: desc = "int8"; break; case PG_INT2: desc = "int2"; break; case PG_INT4: desc = "integer"; break; ! case PG_TEXT: desc = "text"; break; ! case PG_OID: desc = "oid"; break; ! case PG_POINT: desc = "point"; break; case PG_LSEG: desc = "lseg"; break; case PG_PATH: desc = "path"; break; ! case PG_BOX: desc = "box"; break; case PG_POLYGON: desc = "polygon"; break; ! case PG_LINE: desc = "line" ; break; ! case PG_CIDR: desc = "cidr"; break; ! case PG_FLOAT4: desc = "float4"; break; ! case PG_FLOAT8: desc = "float"; break; ! case PG_ABSTIME: desc = "abstime"; break; case PG_RELTIME: desc = "reltime"; break; ! case PG_TINTERVAL: desc = "tinterval"; break; ! case PG_CIRCLE: desc = "circle"; break; ! case PG_CASH: desc = "money"; break; ! case PG_INET: desc = "inet"; break; ! case PG_VARCHAR: desc = "varchar"; break; ! case PG_DATE: desc = "date"; break; case PG_TIME: desc = "time"; break; case PG_TIMESTAMP: desc = "timestamp"; break; ! case PG_INTERVAL: desc = "interval"; break; ! case PG_NUMERIC: desc = "numeric"; break; ! case PG_ROWID: desc = "rowid"; break; ! case PG_BLOB: desc = "blob"; break; default: desc = (char *)NULL; } --- 629,674 ---- switch (fieldType) { + case PG_ABSTIME: desc = "abstime"; break; + case PG_BLOB: desc = "blob"; break; case PG_BOOL: desc = "bool"; break; ! case PG_BOX: desc = "box"; break; case PG_BPCHAR: desc = "char"; break; ! case PG_BYTEA: desc = "bytea"; break; ! case PG_CASH: desc = "money"; break; ! case PG_CHAR: desc = "char"; break; ! case PG_CID: desc = "cid"; break; ! case PG_CIDR: desc = "cidr"; break; ! case PG_CIRCLE: desc = "circle"; break; ! case PG_DATE: desc = "date"; break; ! case PG_FLOAT4: desc = "float4"; break; ! case PG_FLOAT8: desc = "float"; break; ! case PG_INET: desc = "inet"; break; case PG_INT2: desc = "int2"; break; + case PG_INT2VECTOR: desc = "int2vector"; break; case PG_INT4: desc = "integer"; break; ! case PG_INT8: desc = "bigint"; break; ! case PG_INTERVAL: desc = "interval"; break; ! case PG_LINE: desc = "line" ; break; case PG_LSEG: desc = "lseg"; break; + case PG_NAME: desc = "name"; break; + case PG_NUMERIC: desc = "numeric"; break; + case PG_OID: desc = "oid"; break; + case PG_OIDVECTOR: desc = "oidvector"; break; case PG_PATH: desc = "path"; break; ! case PG_POINT: desc = "point"; break; case PG_POLYGON: desc = "polygon"; break; ! case PG_REGPROC: desc = "regproc"; break; case PG_RELTIME: desc = "reltime"; break; ! case PG_ROWID: desc = "rowid"; break; ! case PG_TEXT: desc = "text"; break; ! case PG_TID: desc = "tid"; break; case PG_TIME: desc = "time"; break; case PG_TIMESTAMP: desc = "timestamp"; break; ! case PG_TINTERVAL: desc = "tinterval"; break; ! case PG_UNKNOWN: desc = "unknown"; break; ! case PG_VARBIT: desc = "varbit"; break; ! case PG_VARCHAR: desc = "varchar"; break; ! case PG_XID: desc = "xid"; break; ! case PG_ZPBIT: desc = "zpbit"; break; default: desc = (char *)NULL; } *************** *** 567,570 **** --- 855,862 ---- { "PQconndefaults", (PyCFunction)libPQconndefaults, 1, libPQconndefaults_Doc }, + { "PgQuoteString", (PyCFunction)libPQquoteString, 1, libPQquoteString_Doc }, + { "PgQuoteBytea", (PyCFunction)libPQquoteBytea, 1, libPQquoteBytea_Doc }, + { "PgUnQuoteBytea", (PyCFunction)libPQunQuoteBytea, 1, + libPQunQuoteBytea_Doc }, #if defined(DO_NOT_DEFINE_THIS_MACRO) { "PQconnectStart", (PyCFunction)libPQconnectStart, 1, *************** *** 638,673 **** /*-----------------------------------------------------------------------*/ PyDict_SetItemString(d, "PG_BOOL", Py_BuildValue("i", PG_BOOL)); ! PyDict_SetItemString(d, "PG_CHAR", Py_BuildValue("i", PG_CHAR)); PyDict_SetItemString(d, "PG_BPCHAR", Py_BuildValue("i", PG_BPCHAR)); ! PyDict_SetItemString(d, "PG_NAME", Py_BuildValue("i", PG_NAME)); ! PyDict_SetItemString(d, "PG_INT8", Py_BuildValue("i", PG_INT8)); PyDict_SetItemString(d, "PG_INT2", Py_BuildValue("i", PG_INT2)); PyDict_SetItemString(d, "PG_INT4", Py_BuildValue("i", PG_INT4)); ! PyDict_SetItemString(d, "PG_TEXT", Py_BuildValue("i", PG_TEXT)); ! PyDict_SetItemString(d, "PG_OID", Py_BuildValue("i", PG_OID)); ! PyDict_SetItemString(d, "PG_POINT", Py_BuildValue("i", PG_POINT)); PyDict_SetItemString(d, "PG_LSEG", Py_BuildValue("i", PG_LSEG)); PyDict_SetItemString(d, "PG_PATH", Py_BuildValue("i", PG_PATH)); ! PyDict_SetItemString(d, "PG_BOX", Py_BuildValue("i", PG_BOX)); PyDict_SetItemString(d, "PG_POLYGON", Py_BuildValue("i", PG_POLYGON)); ! PyDict_SetItemString(d, "PG_LINE", Py_BuildValue("i", PG_LINE)); ! PyDict_SetItemString(d, "PG_CIDR", Py_BuildValue("i", PG_CIDR)); ! PyDict_SetItemString(d, "PG_FLOAT4", Py_BuildValue("i", PG_FLOAT4)); ! PyDict_SetItemString(d, "PG_FLOAT8", Py_BuildValue("i", PG_FLOAT8)); ! PyDict_SetItemString(d, "PG_ABSTIME", Py_BuildValue("i", PG_ABSTIME)); PyDict_SetItemString(d, "PG_RELTIME", Py_BuildValue("i", PG_RELTIME)); ! PyDict_SetItemString(d, "PG_TINTERVAL", Py_BuildValue("i", PG_TINTERVAL)); ! PyDict_SetItemString(d, "PG_CIRCLE", Py_BuildValue("i", PG_CIRCLE)); ! PyDict_SetItemString(d, "PG_MONEY", Py_BuildValue("i", PG_CASH)); ! PyDict_SetItemString(d, "PG_INET", Py_BuildValue("i", PG_INET)); ! PyDict_SetItemString(d, "PG_VARCHAR", Py_BuildValue("i", PG_VARCHAR)); ! PyDict_SetItemString(d, "PG_DATE", Py_BuildValue("i", PG_DATE)); PyDict_SetItemString(d, "PG_TIME", Py_BuildValue("i", PG_TIME)); PyDict_SetItemString(d, "PG_TIMESTAMP", Py_BuildValue("i", PG_TIMESTAMP)); ! PyDict_SetItemString(d, "PG_INTERVAL", Py_BuildValue("i", PG_INTERVAL)); ! PyDict_SetItemString(d, "PG_NUMERIC", Py_BuildValue("i", PG_NUMERIC)); ! PyDict_SetItemString(d, "PG_ROWID", Py_BuildValue("i", PG_ROWID)); ! PyDict_SetItemString(d, "PG_BLOB", Py_BuildValue("i", PG_BLOB)); /*-----------------------------------------------------------------------*/ --- 930,975 ---- /*-----------------------------------------------------------------------*/ + PyDict_SetItemString(d, "PG_ABSTIME", Py_BuildValue("i", PG_ABSTIME)); + PyDict_SetItemString(d, "PG_BLOB", Py_BuildValue("i", PG_BLOB)); PyDict_SetItemString(d, "PG_BOOL", Py_BuildValue("i", PG_BOOL)); ! PyDict_SetItemString(d, "PG_BOX", Py_BuildValue("i", PG_BOX)); PyDict_SetItemString(d, "PG_BPCHAR", Py_BuildValue("i", PG_BPCHAR)); ! PyDict_SetItemString(d, "PG_BYTEA", Py_BuildValue("i", PG_BYTEA)); ! PyDict_SetItemString(d, "PG_CHAR", Py_BuildValue("i", PG_CHAR)); ! PyDict_SetItemString(d, "PG_CID", Py_BuildValue("i", PG_CID)); ! PyDict_SetItemString(d, "PG_CIDR", Py_BuildValue("i", PG_CIDR)); ! PyDict_SetItemString(d, "PG_CIRCLE", Py_BuildValue("i", PG_CIRCLE)); ! PyDict_SetItemString(d, "PG_DATE", Py_BuildValue("i", PG_DATE)); ! PyDict_SetItemString(d, "PG_FLOAT4", Py_BuildValue("i", PG_FLOAT4)); ! PyDict_SetItemString(d, "PG_FLOAT8", Py_BuildValue("i", PG_FLOAT8)); ! PyDict_SetItemString(d, "PG_INET", Py_BuildValue("i", PG_INET)); PyDict_SetItemString(d, "PG_INT2", Py_BuildValue("i", PG_INT2)); + PyDict_SetItemString(d, "PG_INT2VECTOR", Py_BuildValue("i", PG_INT2VECTOR)); PyDict_SetItemString(d, "PG_INT4", Py_BuildValue("i", PG_INT4)); ! PyDict_SetItemString(d, "PG_INT8", Py_BuildValue("i", PG_INT8)); ! PyDict_SetItemString(d, "PG_INTERVAL", Py_BuildValue("i", PG_INTERVAL)); ! PyDict_SetItemString(d, "PG_LINE", Py_BuildValue("i", PG_LINE)); PyDict_SetItemString(d, "PG_LSEG", Py_BuildValue("i", PG_LSEG)); + PyDict_SetItemString(d, "PG_MONEY", Py_BuildValue("i", PG_CASH)); + PyDict_SetItemString(d, "PG_NAME", Py_BuildValue("i", PG_NAME)); + PyDict_SetItemString(d, "PG_NUMERIC", Py_BuildValue("i", PG_NUMERIC)); + PyDict_SetItemString(d, "PG_OID", Py_BuildValue("i", PG_OID)); + PyDict_SetItemString(d, "PG_OIDVECTOR", Py_BuildValue("i", PG_OIDVECTOR)); PyDict_SetItemString(d, "PG_PATH", Py_BuildValue("i", PG_PATH)); ! PyDict_SetItemString(d, "PG_POINT", Py_BuildValue("i", PG_POINT)); PyDict_SetItemString(d, "PG_POLYGON", Py_BuildValue("i", PG_POLYGON)); ! PyDict_SetItemString(d, "PG_REGPROC", Py_BuildValue("i", PG_REGPROC)); PyDict_SetItemString(d, "PG_RELTIME", Py_BuildValue("i", PG_RELTIME)); ! PyDict_SetItemString(d, "PG_ROWID", Py_BuildValue("i", PG_ROWID)); ! PyDict_SetItemString(d, "PG_TEXT", Py_BuildValue("i", PG_TEXT)); ! PyDict_SetItemString(d, "PG_TID", Py_BuildValue("i", PG_TID)); PyDict_SetItemString(d, "PG_TIME", Py_BuildValue("i", PG_TIME)); PyDict_SetItemString(d, "PG_TIMESTAMP", Py_BuildValue("i", PG_TIMESTAMP)); ! PyDict_SetItemString(d, "PG_TINTERVAL", Py_BuildValue("i", PG_TINTERVAL)); ! PyDict_SetItemString(d, "PG_UNKNOWN", Py_BuildValue("i", PG_UNKNOWN)); ! PyDict_SetItemString(d, "PG_VARBIT", Py_BuildValue("i", PG_VARBIT)); ! PyDict_SetItemString(d, "PG_VARCHAR", Py_BuildValue("i", PG_VARCHAR)); ! PyDict_SetItemString(d, "PG_XID", Py_BuildValue("i", PG_XID)); ! PyDict_SetItemString(d, "PG_ZPBIT", Py_BuildValue("i", PG_ZPBIT)); /*-----------------------------------------------------------------------*/ Index: pg_types.h =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/pg_types.h,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** pg_types.h 2001/08/31 05:47:44 1.2 --- pg_types.h 2001/09/24 07:10:56 1.3 *************** *** 7,10 **** --- 7,12 ---- #define PG_BPCHAR 1042 + #define PG_BYTEA 17 + /* Number */ #define PG_INT4 23 *************** *** 12,15 **** --- 14,18 ---- #define PG_INT2 21 #define PG_INT8 20 + #define PG_BIGINT PG_INT8 #define PG_OID 26 #define PG_NUMERIC 1700 *************** *** 20,23 **** --- 23,30 ---- #define PG_CASH 790 + #define PG_TID 27 + #define PG_XID 28 + #define PG_CID 29 + /* Temporal */ #define PG_DATE 1082 *************** *** 30,33 **** --- 37,42 ---- #define PG_TINTERVAL 704 + #define PG_TIMETZ 1266 + /* Logical */ #define PG_BOOL 16 *************** *** 45,46 **** --- 54,65 ---- #define PG_INET 869 #define PG_CIDR 650 + + /* Bit strings */ + #define PG_ZPBIT 1560 + #define PG_VARBIT 1562 + + /* Misc. */ + #define PG_REGPROC 24 + #define PG_INT2VECTOR 22 + #define PG_OIDVECTOR 30 + #define PG_UNKNOWN 705 Index: pgconnection.c =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/pgconnection.c,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** pgconnection.c 2001/09/23 15:45:33 1.9 --- pgconnection.c 2001/09/24 07:10:56 1.10 *************** *** 30,33 **** --- 30,37 ---- | --------- --- ------------------------------------------------------- | | 23SEP2001 bga Fixed problem when compiling with gcc. | + | --- [Bug #464123] Removed pgFixEsc(). The need for it no | + | longer exists since we now use a different method of | + | quoting strings that doesn't involve repr(), which in- | + | serted the hex escpae sequences to begin with. | | 22SEP2001 bga Fixed bugs uncovered during testing with the new test | | cases for regression testing. | *************** *** 94,153 **** } - /***********************************************************************\ - | Routine to fix up escape sequence in the query string. Python sends | - | seqences in the form '\xNN', PostgreSQL wants them as '\OOO'. | - |-----------------------------------------------------------------------| - | Note: If the value of the escaped character comes in as octal, then a | - | character encoding such as Latin-2 is in use. If the value of | - | the character is > 127, then the escape sequence is replaced by | - | the actual character. This provides a work-around for an ap- | - | parent problem in PostgreSQL. See bug #455514 for details. | - \***********************************************************************/ - - static char *pgFixEsc(char *src) - { - char *p, *s, *e; - int v; - char obuf[4] = "000"; - char *xbuf = &obuf[1]; - - s = p = src; - while (*p) - { - if ((*s++ = *p++) == '\\') - { - if (*p == 'x' || *p == 'X') - { - *s++ = *p++; - xbuf[0] = *s++ = *p++; - xbuf[1] = *s++ = *p++; - v = strtol(xbuf, &e, 16); - if (e == (xbuf + 2)) - { - s[-1] = (v & 7) + '0'; - v >>= 3; - s[-2] = (v & 7) + '0'; - v >>= 3; - s[-3] = (v & 7) + '0'; - } - } - else if (isdigit(*p)) - { - obuf[0] = *s++ = *p++; - obuf[1] = *s++ = *p++; - obuf[2] = *s++ = *p++; - v = strtol(obuf, &e, 8); - if ((e == &obuf[3]) && (v > 127)) - { - s -= 3; - s[-1] = (char)v; - } - } - } - } - *s = 0; - return src; - } - /*----------------------------------------------------------------------*/ --- 98,101 ---- *************** *** 320,325 **** return NULL; - (void)pgFixEsc(query); - if (self->showQuery) fprintf(stderr, "QUERY: %s\n", query); --- 268,271 ---- *************** *** 404,407 **** --- 350,356 ---- if (!PyArg_ParseTuple(args,"s:sendQuery", &query)) return NULL; + + if (self->showQuery) + fprintf(stderr, "QUERY: %s\n", query); if (!PQsendQuery(PgConnection_Get(self), query)) Index: pgresult.c =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/pgresult.c,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** pgresult.c 2001/09/23 07:26:19 1.11 --- pgresult.c 2001/09/24 07:10:56 1.12 *************** *** 29,38 **** | Date Ini Description | | --------- --- ------------------------------------------------------- | | 21SEP2001 bga I have removed resultErrorMessage as an attribute. It | | doesn't make sense to leave it since it will always be | | None. Why? Because any query that generates an error | | will raise an exception, not return a PgResult. | - | --- Fix a bad bug created by the incomplete removal of the | - | resultErrorMessage attribute. | | 14SEP2001 bga Removed code related to PostgreSQL 6.5.x. We now only | | support PostgreSQL 7.0 and later. | --- 29,37 ---- | Date Ini Description | | --------- --- ------------------------------------------------------- | + | 24SEP2001 bga Added support for the PostgreSQL BYTEA type. | | 21SEP2001 bga I have removed resultErrorMessage as an attribute. It | | doesn't make sense to leave it since it will always be | | None. Why? Because any query that generates an error | | will raise an exception, not return a PgResult. | | 14SEP2001 bga Removed code related to PostgreSQL 6.5.x. We now only | | support PostgreSQL 7.0 and later. | *************** *** 410,413 **** --- 409,414 ---- /*--------------------------------------------------------------------------*/ + extern PyObject *unQuoteBytea(char *); + static char libPQgetvalue_Doc[] = "getvalue(tidx, fidx) -- Returns a single field (attribute) value of " *************** *** 610,613 **** --- 611,618 ---- case PG_FLOAT8: valueObj = Py_BuildValue("d", strtod(value, NULL)); + break; + + case PG_BYTEA: + valueObj = unQuoteBytea(value); break; Index: pgresult.h =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/pgresult.h,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 |