Changeset 798

Show
Ignore:
Timestamp:
03/07/07 17:46:35 (2 years ago)
Author:
mfenniak
Message:

begin working on extended query backend protocol usage

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • pg8000/trunk/pg8000.py

    r797 r798  
    132132            raise InterfaceError("communication error", e) 
    133133 
    134     def execute(self, command, *args, **kwargs): 
     134    def execute(self, command, *args): 
    135135        pass 
    136136 
    137     def query(self, query, *args, **kwargs): 
    138         self._row_desc = self.c.query(query) 
     137    def query(self, query, *args): 
     138        self._row_desc = self.c.extended_query('', '', query, args) 
     139        #self._row_desc = self.c.query(query) 
    139140 
    140141    def _fetch(self): 
     
    142143        if row == None: 
    143144            return None 
    144         return tuple([Types.convert(row.fields[i], self._row_desc.fields[i]) for i in range(len(row.fields))]) 
     145        return tuple([Types.py_value(row.fields[i], self._row_desc.fields[i]) for i in range(len(row.fields))]) 
    145146 
    146147    ## 
     
    217218            return val 
    218219 
     220    class Parse(object): 
     221        def __init__(self, ps, qs, types): 
     222            self.ps = ps 
     223            self.qs = qs 
     224            self.types = [Types.pg_type_id(x) for x in types] 
     225 
     226        def serialize(self): 
     227            val = self.ps + "\x00" + self.qs + "\x00" 
     228            val = val + struct.pack("!h", len(self.types)) 
     229            for oid in self.types: 
     230                val = val + struct.pack("!i", oid) 
     231            val = struct.pack("!i", len(val) + 4) + val 
     232            val = "P" + val 
     233            return val 
     234 
     235    class Bind(object): 
     236        def __init__(self, portal, ps, in_fc, params, out_fc): 
     237            self.portal = portal 
     238            self.ps = ps 
     239            self.in_fc = in_fc 
     240            self.params = [] 
     241            for i in range(len(params)): 
     242                if len(self.in_fc) == 0: 
     243                    fc = 0 
     244                elif len(self.in_fc) == 1: 
     245                    fc = self.in_fc[0] 
     246                else: 
     247                    fc = self.in_fc[i] 
     248                self.params.append(Types.pg_value(params[i], fc)) 
     249            self.out_fc = out_fc 
     250 
     251        def serialize(self): 
     252            val = self.portal + "\x00" + self.ps + "\x00" 
     253            val = val + struct.pack("!h", len(self.in_fc)) 
     254            for fc in self.in_fc: 
     255                val = val + struct.pack("!h", fc) 
     256            val = val + struct.pack("!h", len(self.params)) 
     257            for param in self.params: 
     258                val = val + struct.pack("!i", len(param)) + param 
     259            val = val + struct.pack("!h", len(self.out_fc)) 
     260            for fc in self.out_fc: 
     261                val = val + struct.pack("!h", fc) 
     262            val = struct.pack("!i", len(val) + 4) + val 
     263            val = "B" + val 
     264            return val 
     265 
     266    class Describe(object): 
     267        def __init__(self, typ, name): 
     268            if len(typ) != 1: 
     269                raise InternalError("Describe typ must be 1 char") 
     270            self.typ = typ 
     271            self.name = name 
     272 
     273        def serialize(self): 
     274            val = self.typ + self.name + "\x00" 
     275            val = struct.pack("!i", len(val) + 4) + val 
     276            val = "D" + val 
     277            return val 
     278 
     279    class DescribePortal(Describe): 
     280        def __init__(self, name): 
     281            Protocol.Describe.__init__(self, "P", name) 
     282 
     283    class DescribePreparedStatement(Describe): 
     284        def __init__(self, name): 
     285            Protocol.Describe.__init__(self, "S", name) 
     286 
     287    class Flush(object): 
     288        def serialize(self): 
     289            return 'H\x00\x00\x00\x04' 
     290 
    219291    class PasswordMessage(object): 
    220292        def __init__(self, pwd): 
     
    293365        createFromData = staticmethod(createFromData) 
    294366 
     367    class ParseComplete(object): 
     368        def createFromData(data): 
     369            return Protocol.ParseComplete() 
     370        createFromData = staticmethod(createFromData) 
     371 
     372    class BindComplete(object): 
     373        def createFromData(data): 
     374            return Protocol.BindComplete() 
     375        createFromData = staticmethod(createFromData) 
     376 
    295377    class ReadyForQuery(object): 
    296378        def __init__(self, status): 
     
    425507                    raise msg.createException() 
    426508 
     509        def extended_query(self, portal, statement, qs, params): 
     510            self.verifyState("ready") 
     511            self._send(Protocol.Parse(statement, qs, [type(x) for x in params])) 
     512            self._send(Protocol.Bind(portal, statement, (1,), params, (1,))) 
     513            self._send(Protocol.DescribePortal(portal)) 
     514            self._send(Protocol.Flush()) 
     515            while 1: 
     516                msg = self._read_message() 
     517                if isinstance(msg, Protocol.ParseComplete): 
     518                    # ok, good. 
     519                    pass 
     520                elif isinstance(msg, Protocol.BindComplete): 
     521                    # good news everybody! 
     522                    pass 
     523                elif isinstance(msg, Protocol.RowDescription): 
     524                    return msg 
     525                elif isinstance(msg, Protocol.ErrorResponse): 
     526                    raise msg.createException() 
     527                else: 
     528                    raise InternalError("Unexpected response msg %r" % (msg)) 
     529 
    427530        def query(self, qs): 
    428531            self.verifyState("ready") 
     
    456559        "D": DataRow, 
    457560        "C": CommandComplete, 
     561        "1": ParseComplete, 
     562        "2": BindComplete, 
    458563        } 
    459564 
    460565class Types(object): 
    461     def convert(data, description): 
     566    def pg_type_id(typ): 
     567        data = Types.py_types.get(typ) 
     568        if data == None: 
     569            raise NotSupportedError("type %r not mapped to pg type" % typ) 
     570        type_oid, func_txt, func_bin = data 
     571        return type_oid 
     572    pg_type_id = staticmethod(pg_type_id) 
     573 
     574    def pg_value(v, fc): 
     575        typ = type(v) 
     576        data = Types.py_types.get(typ) 
     577        if data == None: 
     578            raise NotSupportedError("type %r not mapped to pg type" % typ) 
     579        type_oid, func_txt, func_bin = data 
     580        if fc == 0: 
     581            func = func_txt 
     582        else: 
     583            func = func_bin 
     584        if func == None: 
     585            raise NotSupportedError("type %r, format code %r not converted" % (typ, fc)) 
     586        return func(v) 
     587    pg_value = staticmethod(pg_value) 
     588 
     589    def py_value(data, description): 
     590        type_oid = description['type_oid'] 
    462591        format = description['format'] 
    463         table = Types.t_formats.get(format) 
    464         if table == None: 
    465             raise NotSupportedError("data response format %r not supported" % format) 
    466         type_oid = description['type_oid'] 
    467         func = table.get(type_oid) 
     592        funcs = Types.pg_types.get(type_oid) 
     593        if func == None: 
     594            raise NotSupportedError("data response type %r not supported" % (type_oid)) 
     595        func = funcs[format] 
    468596        if func == None: 
    469597            raise NotSupportedError("data response format %r, type %r not supported" % (format, type_oid)) 
    470         in_func, out_func = func 
    471         return in_func(data, description) 
    472     convert = staticmethod(convert) 
     598        return func(data, description) 
     599    py_value = staticmethod(py_value) 
    473600 
    474601    def boolin(data, description): 
    475602        return data == 't' 
    476603 
    477     def boolout(v): 
    478         # imp req. 
    479         pass 
    480  
    481604    def int4in(data, description): 
    482605        return int(data) 
    483606 
    484     def int4out(v): 
    485         # imp req. 
    486         pass 
     607    def int4send(v): 
     608        return struct.pack("!i", v) 
    487609 
    488610    def timestamp_in(data, description): 
     
    495617        return datetime.datetime(year, month, day, hour, minute, sec) 
    496618 
    497     def timestamp_out(v): 
    498         # imp req. 
    499         pass 
    500  
    501     t_formats_text = { 
    502         16: (boolin, boolout), 
    503         23: (int4in, int4out), 
    504         1114: (timestamp_in, timestamp_out), 
     619    py_types = { 
     620        int: (23, None, int4send), 
    505621    } 
    506622 
    507     t_formats = { 
    508         0: t_formats_text, 
     623    pg_types = { 
     624        16: (boolin, None), 
     625        23: (int4in, None), 
     626        1114: (timestamp_in, None), 
    509627    } 
    510628 
  • pg8000/trunk/pg8000-test.py

    r796 r798  
    33import pg8000 
    44 
    5 db = pg8000.Connection(host='joy.fenniak.net', user='Mathieu Fenniak', password='hello', database='software') 
     5db = pg8000.Connection(host='localhost', user='mfenniak') 
    66db.iterate_dicts = True 
    77 
    88print "begin query..." 
    9 db.query("SELECT 5000 + 1, True as pg_stuff, False, '2000-01-02 03:04:05'::timestamp"
     9db.query("SELECT 5000 + 1, True as pg_stuff, False, '2000-01-02 03:04:05'::timestamp, $1", 55
    1010for row in db: 
    1111    print repr(row)