Home | Trees | Indices | Help |
|
---|
|
1 # vim: sw=4:expandtab:foldmethod=marker 2 # 3 # Copyright (c) 2007, Mathieu Fenniak 4 # All rights reserved. 5 # 6 # Redistribution and use in source and binary forms, with or without 7 # modification, are permitted provided that the following conditions are 8 # met: 9 # 10 # * Redistributions of source code must retain the above copyright notice, 11 # this list of conditions and the following disclaimer. 12 # * Redistributions in binary form must reproduce the above copyright notice, 13 # this list of conditions and the following disclaimer in the documentation 14 # and/or other materials provided with the distribution. 15 # * The name of the author may not be used to endorse or promote products 16 # derived from this software without specific prior written permission. 17 # 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 # POSSIBILITY OF SUCH DAMAGE. 29 30 __author__ = "Mathieu Fenniak" 31 32 import socket 33 import threading 34 import struct 35 import md5 36 from cStringIO import StringIO 37 38 from errors import * 39 from util import MulticastDelegate 40 import types41 42 ## 43 # An SSLRequest message. To initiate an SSL-encrypted connection, an 44 # SSLRequest message is used rather than a {@link StartupMessage 45 # StartupMessage}. A StartupMessage is still sent, but only after SSL 46 # negotiation (if accepted). 47 # <p> 48 # Stability: This is an internal class. No stability guarantee is made. 49 -class SSLRequest(object):52 53 # Int32(8) - Message length, including self.<br> 54 # Int32(80877103) - The SSL request code.<br>5758 59 ## 60 # A StartupMessage message. Begins a DB session, identifying the user to be 61 # authenticated as and the database to connect to. 62 # <p> 63 # Stability: This is an internal class. No stability guarantee is made. 64 -class StartupMessage(object):68 69 # Int32 - Message length, including self. 70 # Int32(196608) - Protocol version number. Version 3.0. 71 # Any number of key/value pairs, terminated by a zero byte: 72 # String - A parameter name (user, database, or options) 73 # String - Parameter value8384 85 ## 86 # Parse message. Creates a prepared statement in the DB session. 87 # <p> 88 # Stability: This is an internal class. No stability guarantee is made. 89 # 90 # @param ps Name of the prepared statement to create. 91 # @param qs Query string. 92 # @param type_oids An iterable that contains the PostgreSQL type OIDs for 93 # parameters in the query string. 94 -class Parse(object):99123101 return "<Parse ps=%r qs=%r>" % (self.ps, self.qs)102 103 # Byte1('P') - Identifies the message as a Parse command. 104 # Int32 - Message length, including self. 105 # String - Prepared statement name. An empty string selects the unnamed 106 # prepared statement. 107 # String - The query string. 108 # Int16 - Number of parameter data types specified (can be zero). 109 # For each parameter: 110 # Int32 - The OID of the parameter data type.112 val = self.ps + "\x00" + self.qs + "\x00" 113 val = val + struct.pack("!h", len(self.type_oids)) 114 for oid in self.type_oids: 115 # Parse message doesn't seem to handle the -1 type_oid for NULL 116 # values that other messages handle. So we'll provide type_oid 705, 117 # the PG "unknown" type. 118 if oid == -1: oid = 705 119 val = val + struct.pack("!i", oid) 120 val = struct.pack("!i", len(val) + 4) + val 121 val = "P" + val 122 return val124 125 ## 126 # Bind message. Readies a prepared statement for execution. 127 # <p> 128 # Stability: This is an internal class. No stability guarantee is made. 129 # 130 # @param portal Name of the destination portal. 131 # @param ps Name of the source prepared statement. 132 # @param in_fc An iterable containing the format codes for input 133 # parameters. 0 = Text, 1 = Binary. 134 # @param params The parameters. 135 # @param out_fc An iterable containing the format codes for output 136 # parameters. 0 = Text, 1 = Binary. 137 # @param kwargs Additional arguments to pass to the type conversion 138 # methods. 139 -class Bind(object):196141 self.portal = portal 142 self.ps = ps 143 self.in_fc = in_fc 144 self.params = [] 145 for i in range(len(params)): 146 if len(self.in_fc) == 0: 147 fc = 0 148 elif len(self.in_fc) == 1: 149 fc = self.in_fc[0] 150 else: 151 fc = self.in_fc[i] 152 self.params.append(types.pg_value(params[i], fc, **kwargs)) 153 self.out_fc = out_fc154156 return "<Bind p=%r s=%r>" % (self.portal, self.ps)157 158 # Byte1('B') - Identifies the Bind command. 159 # Int32 - Message length, including self. 160 # String - Name of the destination portal. 161 # String - Name of the source prepared statement. 162 # Int16 - Number of parameter format codes. 163 # For each parameter format code: 164 # Int16 - The parameter format code. 165 # Int16 - Number of parameter values. 166 # For each parameter value: 167 # Int32 - The length of the parameter value, in bytes, not including this 168 # this length. -1 indicates a NULL parameter value, in which no 169 # value bytes follow. 170 # Byte[n] - Value of the parameter. 171 # Int16 - The number of result-column format codes. 172 # For each result-column format code: 173 # Int16 - The format code.175 retval = StringIO() 176 retval.write(self.portal + "\x00") 177 retval.write(self.ps + "\x00") 178 retval.write(struct.pack("!h", len(self.in_fc))) 179 for fc in self.in_fc: 180 retval.write(struct.pack("!h", fc)) 181 retval.write(struct.pack("!h", len(self.params))) 182 for param in self.params: 183 if param == None: 184 # special case, NULL value 185 retval.write(struct.pack("!i", -1)) 186 else: 187 retval.write(struct.pack("!i", len(param))) 188 retval.write(param) 189 retval.write(struct.pack("!h", len(self.out_fc))) 190 for fc in self.out_fc: 191 retval.write(struct.pack("!h", fc)) 192 val = retval.getvalue() 193 val = struct.pack("!i", len(val) + 4) + val 194 val = "B" + val 195 return val197 198 ## 199 # A Close message, used for closing prepared statements and portals. 200 # <p> 201 # Stability: This is an internal class. No stability guarantee is made. 202 # 203 # @param typ 'S' for prepared statement, 'P' for portal. 204 # @param name The name of the item to close. 205 -class Close(object):221207 if len(typ) != 1: 208 raise InternalError("Close typ must be 1 char") 209 self.typ = typ 210 self.name = name211 212 # Byte1('C') - Identifies the message as a close command. 213 # Int32 - Message length, including self. 214 # Byte1 - 'S' for prepared statement, 'P' for portal. 215 # String - The name of the item to close.222 223 ## 224 # A specialized Close message for a portal. 225 # <p> 226 # Stability: This is an internal class. No stability guarantee is made. 227 -class ClosePortal(Close):230231 232 ## 233 # A specialized Close message for a prepared statement. 234 # <p> 235 # Stability: This is an internal class. No stability guarantee is made. 236 -class ClosePreparedStatement(Close):239240 241 ## 242 # A Describe message, used for obtaining information on prepared statements 243 # and portals. 244 # <p> 245 # Stability: This is an internal class. No stability guarantee is made. 246 # 247 # @param typ 'S' for prepared statement, 'P' for portal. 248 # @param name The name of the item to close. 249 -class Describe(object):265251 if len(typ) != 1: 252 raise InternalError("Describe typ must be 1 char") 253 self.typ = typ 254 self.name = name255 256 # Byte1('D') - Identifies the message as a describe command. 257 # Int32 - Message length, including self. 258 # Byte1 - 'S' for prepared statement, 'P' for portal. 259 # String - The name of the item to close.266 267 ## 268 # A specialized Describe message for a portal. 269 # <p> 270 # Stability: This is an internal class. No stability guarantee is made. 271 -class DescribePortal(Describe):277278 279 ## 280 # A specialized Describe message for a prepared statement. 281 # <p> 282 # Stability: This is an internal class. No stability guarantee is made. 283 -class DescribePreparedStatement(Describe):289290 291 ## 292 # A Flush message forces the backend to deliver any data pending in its 293 # output buffers. 294 # <p> 295 # Stability: This is an internal class. No stability guarantee is made. 296 -class Flush(object):297 # Byte1('H') - Identifies the message as a flush command. 298 # Int32(4) - Length of message, including self. 301304305 ## 306 # Causes the backend to close the current transaction (if not in a BEGIN/COMMIT 307 # block), and issue ReadyForQuery. 308 # <p> 309 # Stability: This is an internal class. No stability guarantee is made. 310 -class Sync(object):311 # Byte1('S') - Identifies the message as a sync command. 312 # Int32(4) - Length of message, including self. 315318319 320 ## 321 # Transmits a password. 322 # <p> 323 # Stability: This is an internal class. No stability guarantee is made. 324 -class PasswordMessage(object):327 328 # Byte1('p') - Identifies the message as a password message. 329 # Int32 - Message length including self. 330 # String - The password. Password may be encrypted.336337 338 ## 339 # Requests that the backend execute a portal and retrieve any number of rows. 340 # <p> 341 # Stability: This is an internal class. No stability guarantee is made. 342 # @param row_count The number of rows to return. Can be zero to indicate the 343 # backend should return all rows. If the portal represents a 344 # query that does not return rows, no rows will be returned 345 # no matter what the row_count. 346 -class Execute(object):350 351 # Byte1('E') - Identifies the message as an execute message. 352 # Int32 - Message length, including self. 353 # String - The name of the portal to execute. 354 # Int32 - Maximum number of rows to return, if portal contains a query that 355 # returns rows. 0 = no limit.361357 val = self.portal + "\x00" + struct.pack("!i", self.row_count) 358 val = struct.pack("!i", len(val) + 4) + val 359 val = "E" + val 360 return val362 363 ## 364 # Informs the backend that the connection is being closed. 365 # <p> 366 # Stability: This is an internal class. No stability guarantee is made. 367 -class Terminate(object):370 371 # Byte1('X') - Identifies the message as a terminate message. 372 # Int32(4) - Message length, including self.375376 ## 377 # Base class of all Authentication[*] messages. 378 # <p> 379 # Stability: This is an internal class. No stability guarantee is made. 380 -class AuthenticationRequest(object):383 384 # Byte1('R') - Identifies the message as an authentication request. 385 # Int32(8) - Message length, including self. 386 # Int32 - An authentication code that represents different 387 # authentication messages: 388 # 0 = AuthenticationOk 389 # 5 = MD5 pwd 390 # 2 = Kerberos v5 (not supported by pg8000) 391 # 3 = Cleartext pwd (not supported by pg8000) 392 # 4 = crypt() pwd (not supported by pg8000) 393 # 6 = SCM credential (not supported by pg8000) 394 # 7 = GSSAPI (not supported by pg8000) 395 # 8 = GSSAPI data (not supported by pg8000) 396 # 9 = SSPI (not supported by pg8000) 397 # Some authentication messages have additional data following the 398 # authentication code. That data is documented in the appropriate class.410400 ident = struct.unpack("!i", data[:4])[0] 401 klass = authentication_codes.get(ident, None) 402 if klass != None: 403 return klass(data[4:]) 404 else: 405 raise NotSupportedError("authentication method %r not supported" % (ident,))406 createFromData = staticmethod(createFromData) 407409 raise InternalError("ok method should be overridden on AuthenticationRequest instance")411 ## 412 # A message representing that the backend accepting the provided username 413 # without any challenge. 414 # <p> 415 # Stability: This is an internal class. No stability guarantee is made. 416 -class AuthenticationOk(AuthenticationRequest):419420 421 ## 422 # A message representing the backend requesting an MD5 hashed password 423 # response. The response will be sent as md5(md5(pwd + login) + salt). 424 # <p> 425 # Stability: This is an internal class. No stability guarantee is made. 426 -class AuthenticationMD5Password(AuthenticationRequest):427 # Additional message data: 428 # Byte4 - Hash salt. 431448 449 authentication_codes = { 450 0: AuthenticationOk, 451 5: AuthenticationMD5Password, 452 }433 if password == None: 434 raise InterfaceError("server requesting MD5 password authentication, but no password was provided") 435 pwd = "md5" + md5.new(md5.new(password + user).hexdigest() + self.salt).hexdigest() 436 conn._send(PasswordMessage(pwd)) 437 438 reader = MessageReader(conn) 439 reader.add_message(AuthenticationRequest, lambda msg, reader: reader.return_value(msg.ok(conn, user)), reader) 440 reader.add_message(ErrorResponse, self._ok_error) 441 return reader.handle_messages()442444 if msg.code == "28000": 445 raise InterfaceError("md5 password authentication failed") 446 else: 447 raise msg.createException()453 454 455 ## 456 # ParameterStatus message sent from backend, used to inform the frotnend of 457 # runtime configuration parameter changes. 458 # <p> 459 # Stability: This is an internal class. No stability guarantee is made. 460 -class ParameterStatus(object):464 465 # Byte1('S') - Identifies ParameterStatus 466 # Int32 - Message length, including self. 467 # String - Runtime parameter name. 468 # String - Runtime parameter value.474470 key = data[:data.find("\x00")] 471 value = data[data.find("\x00")+1:-1] 472 return ParameterStatus(key, value)473 createFromData = staticmethod(createFromData)475 476 ## 477 # BackendKeyData message sent from backend. Contains a connection's process 478 # ID and a secret key. Can be used to terminate the connection's current 479 # actions, such as a long running query. Not supported by pg8000 yet. 480 # <p> 481 # Stability: This is an internal class. No stability guarantee is made. 482 -class BackendKeyData(object):486 487 # Byte1('K') - Identifier. 488 # Int32(12) - Message length, including self. 489 # Int32 - Process ID. 490 # Int32 - Secret key.495492 process_id, secret_key = struct.unpack("!2i", data) 493 return BackendKeyData(process_id, secret_key)494 createFromData = staticmethod(createFromData)496 497 ## 498 # Message representing a query with no data. 499 # <p> 500 # Stability: This is an internal class. No stability guarantee is made. 501 -class NoData(object):502 # Byte1('n') - Identifier. 503 # Int32(4) - Message length, including self.507505 return NoData()506 createFromData = staticmethod(createFromData)508 509 ## 510 # Message representing a successful Parse. 511 # <p> 512 # Stability: This is an internal class. No stability guarantee is made. 513 -class ParseComplete(object):514 # Byte1('1') - Identifier. 515 # Int32(4) - Message length, including self.519517 return ParseComplete()518 createFromData = staticmethod(createFromData)520 521 ## 522 # Message representing a successful Bind. 523 # <p> 524 # Stability: This is an internal class. No stability guarantee is made. 525 -class BindComplete(object):526 # Byte1('2') - Identifier. 527 # Int32(4) - Message length, including self.531529 return BindComplete()530 createFromData = staticmethod(createFromData)532 533 ## 534 # Message representing a successful Close. 535 # <p> 536 # Stability: This is an internal class. No stability guarantee is made. 537 -class CloseComplete(object):538 # Byte1('3') - Identifier. 539 # Int32(4) - Message length, including self.543541 return CloseComplete()542 createFromData = staticmethod(createFromData)544 545 ## 546 # Message representing data from an Execute has been received, but more data 547 # exists in the portal. 548 # <p> 549 # Stability: This is an internal class. No stability guarantee is made. 550 -class PortalSuspended(object):551 # Byte1('s') - Identifier. 552 # Int32(4) - Message length, including self.556554 return PortalSuspended()555 createFromData = staticmethod(createFromData)557 558 ## 559 # Message representing the backend is ready to process a new query. 560 # <p> 561 # Stability: This is an internal class. No stability guarantee is made. 562 -class ReadyForQuery(object):580564 self._status = status565 566 ## 567 # I = Idle, T = Idle in Transaction, E = idle in failed transaction. 568 status = property(lambda self: self._status) 569571 return "<ReadyForQuery %s>" % \ 572 {"I": "Idle", "T": "Idle in Transaction", "E": "Idle in Failed Transaction"}[self.status]573 574 # Byte1('Z') - Identifier. 575 # Int32(5) - Message length, including self. 576 # Byte1 - Status indicator.578 return ReadyForQuery(data)579 createFromData = staticmethod(createFromData)581 582 ## 583 # Represents a notice sent from the server. This is not the same as a 584 # notification. A notice is just additional information about a query, such 585 # as a notice that a primary key has automatically been created for a table. 586 # <p> 587 # A NoticeResponse instance will have properties containing the data sent 588 # from the server: 589 # <ul> 590 # <li>severity -- "ERROR", "FATAL', "PANIC", "WARNING", "NOTICE", "DEBUG", 591 # "INFO", or "LOG". Always present.</li> 592 # <li>code -- the SQLSTATE code for the error. See Appendix A of the 593 # PostgreSQL documentation for specific error codes. Always present.</li> 594 # <li>msg -- human-readable error message. Always present.</li> 595 # <li>detail -- Optional additional information.</li> 596 # <li>hint -- Optional suggestion about what to do about the issue.</li> 597 # <li>position -- Optional index into the query string.</li> 598 # <li>where -- Optional context.</li> 599 # <li>file -- Source-code file.</li> 600 # <li>line -- Source-code line.</li> 601 # <li>routine -- Source-code routine.</li> 602 # </ul> 603 # <p> 604 # Stability: Added in pg8000 v1.03. Required properties severity, code, and 605 # msg are guaranteed for v1.xx. Other properties should be checked with 606 # hasattr before accessing. 607 -class NoticeResponse(object):608 responseKeys = { 609 "S": "severity", # always present 610 "C": "code", # always present 611 "M": "msg", # always present 612 "D": "detail", 613 "H": "hint", 614 "P": "position", 615 "p": "_position", 616 "q": "_query", 617 "W": "where", 618 "F": "file", 619 "L": "line", 620 "R": "routine", 621 } 622 626 629648631 retval = {} 632 for s in data.split("\x00"): 633 if not s: continue 634 key, value = s[0], s[1:] 635 key = NoticeResponse.responseKeys.get(key, key) 636 retval[key] = value 637 return retval638 dataIntoDict = staticmethod(dataIntoDict) 639 640 # Byte1('N') - Identifier 641 # Int32 - Message length 642 # Any number of these, followed by a zero byte: 643 # Byte1 - code identifying the field type (see responseKeys) 644 # String - field value 647 createFromData = staticmethod(createFromData)649 650 ## 651 # A message sent in case of a server-side error. Contains the same properties 652 # that {@link NoticeResponse NoticeResponse} contains. 653 # <p> 654 # Stability: Added in pg8000 v1.03. Required properties severity, code, and 655 # msg are guaranteed for v1.xx. Other properties should be checked with 656 # hasattr before accessing. 657 -class ErrorResponse(object):661 664671666 return ProgrammingError(self.severity, self.code, self.msg)667 670 createFromData = staticmethod(createFromData)672 673 ## 674 # A message sent if this connection receives a NOTIFY that it was LISTENing for. 675 # <p> 676 # Stability: Added in pg8000 v1.03. When limited to accessing properties from 677 # a notification event dispatch, stability is guaranteed for v1.xx. 678 -class NotificationResponse(object):716680 self._backend_pid = backend_pid 681 self._condition = condition 682 self._additional_info = additional_info683 684 ## 685 # An integer representing the process ID of the backend that triggered 686 # the NOTIFY. 687 # <p> 688 # Stability: Added in pg8000 v1.03, stability guaranteed for v1.xx. 689 backend_pid = property(lambda self: self._backend_pid) 690 691 ## 692 # The name of the notification fired. 693 # <p> 694 # Stability: Added in pg8000 v1.03, stability guaranteed for v1.xx. 695 condition = property(lambda self: self._condition) 696 697 ## 698 # Currently unspecified by the PostgreSQL documentation as of v8.3.1. 699 # <p> 700 # Stability: Added in pg8000 v1.03, stability guaranteed for v1.xx. 701 additional_info = property(lambda self: self._additional_info) 702704 return "<NotificationResponse %s %s %r>" % (self.backend_pid, self.condition, self.additional_info)705707 backend_pid = struct.unpack("!i", data[:4])[0] 708 data = data[4:] 709 null = data.find("\x00") 710 condition = data[:null] 711 data = data[null+1:] 712 null = data.find("\x00") 713 additional_info = data[:null] 714 return NotificationResponse(backend_pid, condition, additional_info)715 createFromData = staticmethod(createFromData)726722 count = struct.unpack("!h", data[:2])[0] 723 type_oids = struct.unpack("!" + "i"*count, data[2:]) 724 return ParameterDescription(type_oids)725 createFromData = staticmethod(createFromData)731745733 count = struct.unpack("!h", data[:2])[0] 734 data = data[2:] 735 fields = [] 736 for i in range(count): 737 null = data.find("\x00") 738 field = {"name": data[:null]} 739 data = data[null+1:] 740 field["table_oid"], field["column_attrnum"], field["type_oid"], field["type_size"], field["type_modifier"], field["format"] = struct.unpack("!ihihih", data[:18]) 741 data = data[18:] 742 fields.append(field) 743 return RowDescription(fields)744 createFromData = staticmethod(createFromData)752765754 values = data[:-1].split(" ") 755 args = {} 756 args['command'] = values[0] 757 if args['command'] in ("INSERT", "DELETE", "UPDATE", "MOVE", "FETCH", "COPY"): 758 args['rows'] = int(values[-1]) 759 if args['command'] == "INSERT": 760 args['oid'] = int(values[1]) 761 else: 762 args['command'] = data[:-1] 763 return CommandComplete(**args)764 createFromData = staticmethod(createFromData)770785 794772 count = struct.unpack("!h", data[:2])[0] 773 data = data[2:] 774 fields = [] 775 for i in range(count): 776 val_len = struct.unpack("!i", data[:4])[0] 777 data = data[4:] 778 if val_len == -1: 779 fields.append(None) 780 else: 781 fields.append(data[:val_len]) 782 data = data[val_len:] 783 return DataRow(fields)784 createFromData = staticmethod(createFromData)853798 self._conn = connection 799 self._msgs = [] 800 801 # If true, raise exception from an ErrorResponse after messages are 802 # processed. This can be used to leave the connection in a usable 803 # state after an error response, rather than having unconsumed 804 # messages that won't be understood in another context. 805 self.delay_raising_exception = False 806 807 self.ignore_unhandled_messages = False808 811 814 817819 exc = None 820 while 1: 821 msg = self._conn._read_message() 822 msg_handled = False 823 for (msg_class, handler, args, kwargs) in self._msgs: 824 if isinstance(msg, msg_class): 825 msg_handled = True 826 retval = handler(msg, *args, **kwargs) 827 if retval: 828 # The handler returned a true value, meaning that the 829 # message loop should be aborted. 830 if exc != None: 831 raise exc 832 return retval 833 elif hasattr(self, "_retval"): 834 # The handler told us to return -- used for non-true 835 # return values 836 if exc != None: 837 raise exc 838 return self._retval 839 if msg_handled: 840 continue 841 elif isinstance(msg, ErrorResponse): 842 exc = msg.createException() 843 if not self.delay_raising_exception: 844 raise exc 845 elif isinstance(msg, NoticeResponse): 846 self._conn.handleNoticeResponse(msg) 847 elif isinstance(msg, ParameterStatus): 848 self._conn.handleParameterStatus(msg) 849 elif isinstance(msg, NotificationResponse): 850 self._conn.handleNotificationResponse(msg) 851 elif not self.ignore_unhandled_messages: 852 raise InternalError("Unexpected response msg %r" % (msg))855 def _fn(self, *args, **kwargs): 856 try: 857 return fn(self, *args, **kwargs) 858 except: 859 self._sync() 860 raise861 return _fn 8621158 1159 message_types = { 1160 "N": NoticeResponse, 1161 "R": AuthenticationRequest, 1162 "S": ParameterStatus, 1163 "K": BackendKeyData, 1164 "Z": ReadyForQuery, 1165 "T": RowDescription, 1166 "E": ErrorResponse, 1167 "D": DataRow, 1168 "C": CommandComplete, 1169 "1": ParseComplete, 1170 "2": BindComplete, 1171 "3": CloseComplete, 1172 "s": PortalSuspended, 1173 "n": NoData, 1174 "t": ParameterDescription, 1175 "A": NotificationResponse, 1176 } 1177865 self._client_encoding = "ascii" 866 self._integer_datetimes = False 867 if unix_sock == None and host != None: 868 self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 869 elif unix_sock != None: 870 if not hasattr(socket, "AF_UNIX"): 871 raise InterfaceError("attempt to connect to unix socket on unsupported platform") 872 self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 873 else: 874 raise ProgrammingError("one of host or unix_sock must be provided") 875 if unix_sock == None and host != None: 876 self._sock.connect((host, port)) 877 elif unix_sock != None: 878 self._sock.connect(unix_sock) 879 if ssl: 880 self._send(SSLRequest()) 881 resp = self._sock.recv(1) 882 if resp == 'S': 883 self._sock = SSLWrapper(socket.ssl(self._sock)) 884 else: 885 raise InterfaceError("server refuses SSL") 886 else: 887 # settimeout causes ssl failure, on windows. Python bug 1462352. 888 self._sock.settimeout(socket_timeout) 889 self._state = "noauth" 890 self._backend_key_data = None 891 self._sock_lock = threading.Lock() 892 893 self.NoticeReceived = MulticastDelegate() 894 self.ParameterStatusReceived = MulticastDelegate() 895 self.NotificationReceived = MulticastDelegate() 896 897 self.ParameterStatusReceived += self._onParameterStatusReceived898900 if self._state != state: 901 raise InternalError("connection state must be %s, is %s" % (state, self._state))902 907909 bytes = "" 910 while len(bytes) < 5: 911 tmp = self._sock.recv(5 - len(bytes)) 912 bytes += tmp 913 if len(bytes) != 5: 914 raise InternalError("unable to read 5 bytes from socket %r" % bytes) 915 message_code = bytes[0] 916 data_len = struct.unpack("!i", bytes[1:])[0] - 4 917 if data_len == 0: 918 bytes = "" 919 else: 920 bytes = "" 921 while len(bytes) < data_len: 922 tmp = self._sock.recv(data_len - len(bytes)) 923 bytes += tmp 924 assert len(bytes) == data_len 925 msg = message_types[message_code].createFromData(bytes) 926 #print "_read_message() -> %r" % msg 927 return msg928930 self.verifyState("noauth") 931 self._sock_lock.acquire() 932 try: 933 self._send(StartupMessage(user, database=kwargs.get("database",None))) 934 msg = self._read_message() 935 if not isinstance(msg, AuthenticationRequest): 936 raise InternalError("StartupMessage was responded to with non-AuthenticationRequest msg %r" % msg) 937 if not msg.ok(self, user, **kwargs): 938 raise InterfaceError("authentication method %s failed" % msg.__class__.__name__) 939 940 self._state = "auth" 941 942 reader = MessageReader(self) 943 reader.add_message(ReadyForQuery, self._ready_for_query) 944 reader.add_message(BackendKeyData, self._receive_backend_key_data) 945 reader.handle_messages() 946 finally: 947 self._sock_lock.release()948 952 955 956 @sync_on_error958 self.verifyState("ready") 959 self._sock_lock.acquire() 960 try: 961 type_info = [types.pg_type_info(x) for x in param_types] 962 param_types, param_fc = [x[0] for x in type_info], [x[1] for x in type_info] # zip(*type_info) -- fails on empty arr 963 self._send(Parse(statement, qs, param_types)) 964 self._send(DescribePreparedStatement(statement)) 965 self._send(Flush()) 966 967 reader = MessageReader(self) 968 969 # ParseComplete is good. 970 reader.add_message(ParseComplete, lambda msg: 0) 971 972 # Well, we don't really care -- we're going to send whatever we 973 # want and let the database deal with it. But thanks anyways! 974 reader.add_message(ParameterDescription, lambda msg: 0) 975 976 # We're not waiting for a row description. Return something 977 # destinctive to let bind know that there is no output. 978 reader.add_message(NoData, lambda msg: (None, param_fc)) 979 980 # Common row description response 981 reader.add_message(RowDescription, lambda msg: (msg, param_fc)) 982 983 return reader.handle_messages() 984 985 finally: 986 self._sock_lock.release()987 988 @sync_on_error990 self.verifyState("ready") 991 self._sock_lock.acquire() 992 try: 993 row_desc, param_fc = parse_data 994 if row_desc == None: 995 # no data coming out 996 output_fc = () 997 else: 998 # We've got row_desc that allows us to identify what we're going to 999 # get back from this statement. 1000 output_fc = [types.py_type_info(f) for f in row_desc.fields] 1001 self._send(Bind(portal, statement, param_fc, params, output_fc, client_encoding = self._client_encoding, integer_datetimes = self._integer_datetimes)) 1002 # We need to describe the portal after bind, since the return 1003 # format codes will be different (hopefully, always what we 1004 # requested). 1005 self._send(DescribePortal(portal)) 1006 self._send(Flush()) 1007 1008 # Read responses from server... 1009 reader = MessageReader(self) 1010 1011 # BindComplete is good -- just ignore 1012 reader.add_message(BindComplete, lambda msg: 0) 1013 1014 # NoData in this case means we're not executing a query. As a 1015 # result, we won't be fetching rows, so we'll never execute the 1016 # portal we just created... unless we execute it right away, which 1017 # we'll do. 1018 reader.add_message(NoData, self._bind_nodata, portal, reader) 1019 1020 # Return the new row desc, since it will have the format types we 1021 # asked the server for 1022 reader.add_message(RowDescription, lambda msg: (msg, None)) 1023 1024 return reader.handle_messages() 1025 1026 finally: 1027 self._sock_lock.release()10281030 # Bind message returned NoData, causing us to execute the command. 1031 self._send(Execute(portal, 0)) 1032 self._send(Sync()) 1033 1034 output = {} 1035 reader = MessageReader(self) 1036 reader.add_message(CommandComplete, lambda msg, out: out.setdefault('msg', msg) and False, output) 1037 reader.add_message(ReadyForQuery, lambda msg: 1) 1038 reader.delay_raising_exception = True 1039 reader.handle_messages() 1040 1041 old_reader.return_value((None, output['msg']))1042 1043 @sync_on_error1045 self.verifyState("ready") 1046 self._sock_lock.acquire() 1047 try: 1048 self._send(Execute(portal, row_count)) 1049 self._send(Flush()) 1050 rows = [] 1051 1052 reader = MessageReader(self) 1053 reader.add_message(DataRow, self._fetch_datarow, rows, row_desc) 1054 reader.add_message(PortalSuspended, lambda msg: 1) 1055 reader.add_message(CommandComplete, self._fetch_commandcomplete, portal) 1056 retval = reader.handle_messages() 1057 1058 # retval = 2 when command complete, indicating that we've hit the 1059 # end of the available data for this command 1060 return (retval == 2), rows 1061 finally: 1062 self._sock_lock.release()10631065 rows.append( 1066 [ 1067 types.py_value( 1068 msg.fields[i], 1069 row_desc.fields[i], 1070 client_encoding=self._client_encoding, 1071 integer_datetimes=self._integer_datetimes 1072 ) 1073 for i in range(len(msg.fields)) 1074 ] 1075 )10761078 self._send(ClosePortal(portal)) 1079 self._send(Sync()) 1080 1081 reader = MessageReader(self) 1082 reader.add_message(ReadyForQuery, self._fetch_commandcomplete_rfq) 1083 reader.add_message(CloseComplete, lambda msg: False) 1084 reader.handle_messages() 1085 1086 return 2 # signal end-of-data1087 1091 1092 # Send a Sync message, then read and discard all messages until we 1093 # receive a ReadyForQuery message.1095 self._send(Sync()) 1096 reader = MessageReader(self) 1097 reader.ignore_unhandled_messages = True 1098 reader.add_message(ReadyForQuery, lambda msg: True) 1099 reader.handle_messages()1100 1101 @sync_on_error1103 if self._state == "closed": 1104 return 1105 self.verifyState("ready") 1106 self._sock_lock.acquire() 1107 try: 1108 self._send(ClosePreparedStatement(statement)) 1109 self._send(Sync()) 1110 1111 reader = MessageReader(self) 1112 reader.add_message(CloseComplete, lambda msg: 0) 1113 reader.add_message(ReadyForQuery, lambda msg: 1) 1114 reader.handle_messages() 1115 finally: 1116 self._sock_lock.release()1117 1118 @sync_on_error1120 if self._state == "closed": 1121 return 1122 self.verifyState("ready") 1123 self._sock_lock.acquire() 1124 try: 1125 self._send(ClosePortal(portal)) 1126 self._send(Sync()) 1127 1128 reader = MessageReader(self) 1129 reader.add_message(CloseComplete, lambda msg: 0) 1130 reader.add_message(ReadyForQuery, lambda msg: 1) 1131 reader.handle_messages() 1132 finally: 1133 self._sock_lock.release()11341136 self._sock_lock.acquire() 1137 try: 1138 self._send(Terminate()) 1139 self._sock.close() 1140 self._state = "closed" 1141 finally: 1142 self._sock_lock.release()11431145 if msg.key == "client_encoding": 1146 self._client_encoding = msg.value 1147 elif msg.key == "integer_datetimes": 1148 self._integer_datetimes = (msg.value == "on")11491151 self.NoticeReceived(msg)11521154 self.ParameterStatusReceived(msg)11551157 self.NotificationReceived(msg)
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Thu Jul 17 21:16:48 2008 | http://epydoc.sourceforge.net |