mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-10-31 07:47:30 +03:00 
			
		
		
		
	Add ReplicationMessage object
This commit is contained in:
		
							parent
							
								
									f7b84ce843
								
							
						
					
					
						commit
						453830f80c
					
				|  | @ -574,6 +574,10 @@ class ReplicationCursor(_cursor): | ||||||
| 
 | 
 | ||||||
|         return self.start_replication_expert(o, command, keepalive_interval) |         return self.start_replication_expert(o, command, keepalive_interval) | ||||||
| 
 | 
 | ||||||
|  |     # thin wrapper | ||||||
|  |     def sync_server(self, msg): | ||||||
|  |         return self.replication_sync_server(msg) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| # a dbtype and adapter for Python UUID type | # a dbtype and adapter for Python UUID type | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -72,7 +72,10 @@ struct cursorObject { | ||||||
| #define DEFAULT_COPYSIZE 16384 | #define DEFAULT_COPYSIZE 16384 | ||||||
| #define DEFAULT_COPYBUFF  8192 | #define DEFAULT_COPYBUFF  8192 | ||||||
| 
 | 
 | ||||||
|  |     int   in_replication;       /* we're in streaming replication loop */ | ||||||
|  |     int   stop_replication;     /* client requested to stop replication */ | ||||||
|     int   keepalive_interval;   /* interval for keepalive messages in replication mode */ |     int   keepalive_interval;   /* interval for keepalive messages in replication mode */ | ||||||
|  |     replicationMessageObject *repl_sync_msg;    /* set when the client asks us to sync the server */ | ||||||
| 
 | 
 | ||||||
|     PyObject *tuple_factory;    /* factory for result tuples */ |     PyObject *tuple_factory;    /* factory for result tuples */ | ||||||
|     PyObject *tzinfo_factory;   /* factory for tzinfo objects */ |     PyObject *tzinfo_factory;   /* factory for tzinfo objects */ | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "psycopg/cursor.h" | #include "psycopg/cursor.h" | ||||||
| #include "psycopg/connection.h" | #include "psycopg/connection.h" | ||||||
|  | #include "psycopg/replication_message.h" | ||||||
| #include "psycopg/green.h" | #include "psycopg/green.h" | ||||||
| #include "psycopg/pqpath.h" | #include "psycopg/pqpath.h" | ||||||
| #include "psycopg/typecast.h" | #include "psycopg/typecast.h" | ||||||
|  | @ -1605,17 +1606,68 @@ psyco_curs_start_replication_expert(cursorObject *self, PyObject *args) | ||||||
|     self->copysize = 0; |     self->copysize = 0; | ||||||
|     Py_INCREF(file); |     Py_INCREF(file); | ||||||
|     self->copyfile = file; |     self->copyfile = file; | ||||||
|  |     self->in_replication = 1; | ||||||
|     self->keepalive_interval = keepalive_interval; |     self->keepalive_interval = keepalive_interval; | ||||||
|  |     self->stop_replication = 0; | ||||||
|  |     self->repl_sync_msg = NULL; | ||||||
| 
 | 
 | ||||||
|     if (pq_execute(self, command, 0, 1 /* no_result */, 1 /* no_begin */) >= 0) { |     if (pq_execute(self, command, 0, 1 /* no_result */, 1 /* no_begin */) >= 0) { | ||||||
|         res = Py_None; |         res = Py_None; | ||||||
|         Py_INCREF(Py_None); |         Py_INCREF(Py_None); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     Py_CLEAR(self->repl_sync_msg); | ||||||
|     Py_CLEAR(self->copyfile); |     Py_CLEAR(self->copyfile); | ||||||
|  |     self->in_replication = 0; | ||||||
| 
 | 
 | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #define psyco_curs_stop_replication_doc \ | ||||||
|  | "start_replication() -- Set flag to break out of endless loop in start_replication()." | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | psyco_curs_stop_replication(cursorObject *self) | ||||||
|  | { | ||||||
|  |     EXC_IF_CURS_CLOSED(self); | ||||||
|  | 
 | ||||||
|  |     if (!self->in_replication) { | ||||||
|  |         PyErr_SetString(ProgrammingError, | ||||||
|  |                         "stop_replication() called when not in streaming replication loop"); | ||||||
|  |     } else { | ||||||
|  |         self->stop_replication = 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Py_RETURN_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define psyco_curs_replication_sync_server_doc \ | ||||||
|  | "replication_sync_server(msg) -- Set flag to sync the server up to this replication message." | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | psyco_curs_replication_sync_server(cursorObject *self, PyObject *args) | ||||||
|  | { | ||||||
|  |     replicationMessageObject *msg; | ||||||
|  | 
 | ||||||
|  |     EXC_IF_CURS_CLOSED(self); | ||||||
|  | 
 | ||||||
|  |     if (!PyArg_ParseTuple(args, "O!", &replicationMessageType, &msg)) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!self->in_replication) { | ||||||
|  |         PyErr_SetString(ProgrammingError, | ||||||
|  |                         "replication_sync_server() called when not in streaming replication loop"); | ||||||
|  |     } else { | ||||||
|  |         Py_CLEAR(self->repl_sync_msg); | ||||||
|  | 
 | ||||||
|  |         self->repl_sync_msg = msg; | ||||||
|  |         Py_XINCREF(self->repl_sync_msg); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Py_RETURN_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* extension: closed - return true if cursor is closed */ | /* extension: closed - return true if cursor is closed */ | ||||||
| 
 | 
 | ||||||
| #define psyco_curs_closed_doc \ | #define psyco_curs_closed_doc \ | ||||||
|  | @ -1792,6 +1844,10 @@ static struct PyMethodDef cursorObject_methods[] = { | ||||||
|      METH_VARARGS|METH_KEYWORDS, psyco_curs_copy_expert_doc}, |      METH_VARARGS|METH_KEYWORDS, psyco_curs_copy_expert_doc}, | ||||||
|     {"start_replication_expert", (PyCFunction)psyco_curs_start_replication_expert, |     {"start_replication_expert", (PyCFunction)psyco_curs_start_replication_expert, | ||||||
|      METH_VARARGS, psyco_curs_start_replication_expert_doc}, |      METH_VARARGS, psyco_curs_start_replication_expert_doc}, | ||||||
|  |     {"stop_replication", (PyCFunction)psyco_curs_stop_replication, | ||||||
|  |      METH_NOARGS, psyco_curs_stop_replication_doc}, | ||||||
|  |     {"replication_sync_server", (PyCFunction)psyco_curs_replication_sync_server, | ||||||
|  |      METH_VARARGS, psyco_curs_replication_sync_server_doc}, | ||||||
|     {NULL} |     {NULL} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -1908,6 +1964,7 @@ cursor_clear(cursorObject *self) | ||||||
|     Py_CLEAR(self->casts); |     Py_CLEAR(self->casts); | ||||||
|     Py_CLEAR(self->caster); |     Py_CLEAR(self->caster); | ||||||
|     Py_CLEAR(self->copyfile); |     Py_CLEAR(self->copyfile); | ||||||
|  |     Py_CLEAR(self->repl_sync_msg); | ||||||
|     Py_CLEAR(self->tuple_factory); |     Py_CLEAR(self->tuple_factory); | ||||||
|     Py_CLEAR(self->tzinfo_factory); |     Py_CLEAR(self->tzinfo_factory); | ||||||
|     Py_CLEAR(self->query); |     Py_CLEAR(self->query); | ||||||
|  | @ -1997,6 +2054,7 @@ cursor_traverse(cursorObject *self, visitproc visit, void *arg) | ||||||
|     Py_VISIT(self->casts); |     Py_VISIT(self->casts); | ||||||
|     Py_VISIT(self->caster); |     Py_VISIT(self->caster); | ||||||
|     Py_VISIT(self->copyfile); |     Py_VISIT(self->copyfile); | ||||||
|  |     Py_VISIT(self->repl_sync_msg); | ||||||
|     Py_VISIT(self->tuple_factory); |     Py_VISIT(self->tuple_factory); | ||||||
|     Py_VISIT(self->tzinfo_factory); |     Py_VISIT(self->tzinfo_factory); | ||||||
|     Py_VISIT(self->query); |     Py_VISIT(self->query); | ||||||
|  |  | ||||||
|  | @ -33,6 +33,10 @@ typedef unsigned PG_INT64_TYPE XLogRecPtr; | ||||||
| 
 | 
 | ||||||
| #define InvalidXLogRecPtr ((XLogRecPtr) 0) | #define InvalidXLogRecPtr ((XLogRecPtr) 0) | ||||||
| 
 | 
 | ||||||
|  | /* have to use lowercase %x, as PyString_FromFormat can't do %X */ | ||||||
|  | #define XLOGFMTSTR "%x/%x" | ||||||
|  | #define XLOGFMTARGS(x) ((uint32)((x) >> 32)), ((uint32)((x) & 0xFFFFFFFF)) | ||||||
|  | 
 | ||||||
| HIDDEN pg_int64 feGetCurrentTimestamp(void); | HIDDEN pg_int64 feGetCurrentTimestamp(void); | ||||||
| HIDDEN void fe_sendint64(pg_int64 i, char *buf); | HIDDEN void fe_sendint64(pg_int64 i, char *buf); | ||||||
| HIDDEN pg_int64 fe_recvint64(char *buf); | HIDDEN pg_int64 fe_recvint64(char *buf); | ||||||
|  |  | ||||||
|  | @ -35,6 +35,7 @@ | ||||||
| #include "psycopg/pqpath.h" | #include "psycopg/pqpath.h" | ||||||
| #include "psycopg/connection.h" | #include "psycopg/connection.h" | ||||||
| #include "psycopg/cursor.h" | #include "psycopg/cursor.h" | ||||||
|  | #include "psycopg/replication_message.h" | ||||||
| #include "psycopg/green.h" | #include "psycopg/green.h" | ||||||
| #include "psycopg/typecast.h" | #include "psycopg/typecast.h" | ||||||
| #include "psycopg/pgtypes.h" | #include "psycopg/pgtypes.h" | ||||||
|  | @ -1528,9 +1529,8 @@ sendFeedback(PGconn *conn, XLogRecPtr written_lsn, XLogRecPtr fsync_lsn, | ||||||
|     char replybuf[1 + 8 + 8 + 8 + 8 + 1]; |     char replybuf[1 + 8 + 8 + 8 + 8 + 1]; | ||||||
|     int len = 0; |     int len = 0; | ||||||
| 
 | 
 | ||||||
|     Dprintf("_pq_copy_both_v3: confirming write up to %X/%X, flush to %X/%X\n", |     Dprintf("_pq_copy_both_v3: confirming write up to "XLOGFMTSTR", flush to "XLOGFMTSTR, | ||||||
|             (uint32) (written_lsn >> 32), (uint32) written_lsn, |             XLOGFMTARGS(written_lsn), XLOGFMTARGS(fsync_lsn)); | ||||||
|             (uint32) (fsync_lsn >> 32), (uint32) fsync_lsn); |  | ||||||
| 
 | 
 | ||||||
|     replybuf[len] = 'r'; |     replybuf[len] = 'r'; | ||||||
|     len += 1; |     len += 1; | ||||||
|  | @ -1559,6 +1559,7 @@ _pq_copy_both_v3(cursorObject *curs) | ||||||
|     PyObject *tmp = NULL; |     PyObject *tmp = NULL; | ||||||
|     PyObject *write_func = NULL; |     PyObject *write_func = NULL; | ||||||
|     PyObject *obj = NULL; |     PyObject *obj = NULL; | ||||||
|  |     replicationMessageObject *msg = NULL; | ||||||
|     int ret = -1; |     int ret = -1; | ||||||
|     int is_text; |     int is_text; | ||||||
| 
 | 
 | ||||||
|  | @ -1568,9 +1569,9 @@ _pq_copy_both_v3(cursorObject *curs) | ||||||
|     struct timeval last_comm, curr_time, ping_time, time_diff; |     struct timeval last_comm, curr_time, ping_time, time_diff; | ||||||
|     int len, hdr, reply, sel; |     int len, hdr, reply, sel; | ||||||
| 
 | 
 | ||||||
|     XLogRecPtr written_lsn = InvalidXLogRecPtr; |     XLogRecPtr written_lsn = InvalidXLogRecPtr, | ||||||
|     XLogRecPtr fsync_lsn = InvalidXLogRecPtr; |         fsync_lsn = InvalidXLogRecPtr, | ||||||
|     XLogRecPtr wal_end = InvalidXLogRecPtr; |         data_start, wal_end; | ||||||
| 
 | 
 | ||||||
|     if (!curs->copyfile) { |     if (!curs->copyfile) { | ||||||
|         PyErr_SetString(ProgrammingError, |         PyErr_SetString(ProgrammingError, | ||||||
|  | @ -1666,7 +1667,12 @@ _pq_copy_both_v3(cursorObject *curs) | ||||||
|                     goto exit; |                     goto exit; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 data_start = fe_recvint64(buffer + 1); | ||||||
|                 wal_end    = fe_recvint64(buffer + 1 + 8); |                 wal_end    = fe_recvint64(buffer + 1 + 8); | ||||||
|  |                 /*send_time  = fe_recvint64(buffer + 1 + 8 + 8);*/ | ||||||
|  | 
 | ||||||
|  |                 Dprintf("_pq_copy_both_v3: data_start="XLOGFMTSTR", wal_end="XLOGFMTSTR, | ||||||
|  |                         XLOGFMTARGS(data_start), XLOGFMTARGS(wal_end)); | ||||||
| 
 | 
 | ||||||
|                 if (is_text) { |                 if (is_text) { | ||||||
|                     obj = PyUnicode_Decode(buffer + hdr, len - hdr, curs->conn->codec, NULL); |                     obj = PyUnicode_Decode(buffer + hdr, len - hdr, curs->conn->codec, NULL); | ||||||
|  | @ -1676,21 +1682,36 @@ _pq_copy_both_v3(cursorObject *curs) | ||||||
|                 } |                 } | ||||||
|                 if (!obj) { goto exit; } |                 if (!obj) { goto exit; } | ||||||
| 
 | 
 | ||||||
|                 tmp = PyObject_CallFunctionObjArgs(write_func, obj, NULL); |                 msg = (replicationMessageObject *) | ||||||
|  |                     PyObject_CallFunctionObjArgs((PyObject *)&replicationMessageType, | ||||||
|  |                                                  obj, NULL); | ||||||
|                 Py_DECREF(obj); |                 Py_DECREF(obj); | ||||||
|  |                 if (!msg) { goto exit; } | ||||||
|  | 
 | ||||||
|  |                 msg->data_start = data_start; | ||||||
|  |                 msg->wal_end = wal_end; | ||||||
|  | 
 | ||||||
|  |                 tmp = PyObject_CallFunctionObjArgs(write_func, msg, NULL); | ||||||
| 
 | 
 | ||||||
|                 if (tmp == NULL) { |                 if (tmp == NULL) { | ||||||
|                     Dprintf("_pq_copy_both_v3: write_func returned NULL"); |                     Dprintf("_pq_copy_both_v3: write_func returned NULL"); | ||||||
|                     goto exit; |                     goto exit; | ||||||
|                 } |                 } | ||||||
|  |                 Py_DECREF(tmp); | ||||||
| 
 | 
 | ||||||
|                 /* update the LSN position we've written up to */ |                 /* update the LSN position we've written up to */ | ||||||
|                 if (written_lsn < wal_end) |                 if (written_lsn < wal_end) | ||||||
|                     written_lsn = wal_end; |                     written_lsn = wal_end; | ||||||
| 
 | 
 | ||||||
|                 /* if write() returned true-ish, we confirm LSN with the server */ |                 /* if requested by sync_server(msg), we confirm LSN with the server */ | ||||||
|                 if (PyObject_IsTrue(tmp)) { |                 if (curs->repl_sync_msg) { | ||||||
|                     fsync_lsn = written_lsn; |                     Dprintf("_pq_copy_both_v3: server sync requested at "XLOGFMTSTR, | ||||||
|  |                             XLOGFMTARGS(curs->repl_sync_msg->wal_end)); | ||||||
|  | 
 | ||||||
|  |                     if (fsync_lsn < curs->repl_sync_msg->wal_end) | ||||||
|  |                         fsync_lsn = curs->repl_sync_msg->wal_end; | ||||||
|  | 
 | ||||||
|  |                     Py_CLEAR(curs->repl_sync_msg); | ||||||
| 
 | 
 | ||||||
|                     if (!sendFeedback(conn, written_lsn, fsync_lsn, 0)) { |                     if (!sendFeedback(conn, written_lsn, fsync_lsn, 0)) { | ||||||
|                         pq_raise(curs->conn, curs, NULL); |                         pq_raise(curs->conn, curs, NULL); | ||||||
|  | @ -1698,8 +1719,14 @@ _pq_copy_both_v3(cursorObject *curs) | ||||||
|                     } |                     } | ||||||
|                     gettimeofday(&last_comm, NULL); |                     gettimeofday(&last_comm, NULL); | ||||||
|                 } |                 } | ||||||
|                 Py_DECREF(tmp); |  | ||||||
| 
 | 
 | ||||||
|  |                 if (curs->stop_replication) { | ||||||
|  |                     Dprintf("_pq_copy_both_v3: stop_replication flag set by write_func"); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 Py_DECREF(msg); | ||||||
|  |                 msg = NULL; | ||||||
|             } |             } | ||||||
|             else if (buffer[0] == 'k') { |             else if (buffer[0] == 'k') { | ||||||
|                 /* msgtype(1), walEnd(8), sendTime(8), reply(1) */ |                 /* msgtype(1), walEnd(8), sendTime(8), reply(1) */ | ||||||
|  | @ -1751,6 +1778,7 @@ exit: | ||||||
|         PQfreemem(buffer); |         PQfreemem(buffer); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     Py_XDECREF(msg); | ||||||
|     Py_XDECREF(write_func); |     Py_XDECREF(write_func); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -117,6 +117,7 @@ HIDDEN PyObject *psyco_GetDecimalType(void); | ||||||
| /* forward declarations */ | /* forward declarations */ | ||||||
| typedef struct cursorObject cursorObject; | typedef struct cursorObject cursorObject; | ||||||
| typedef struct connectionObject connectionObject; | typedef struct connectionObject connectionObject; | ||||||
|  | typedef struct replicationMessageObject replicationMessageObject; | ||||||
| 
 | 
 | ||||||
| /* some utility functions */ | /* some utility functions */ | ||||||
| RAISES HIDDEN PyObject *psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg); | RAISES HIDDEN PyObject *psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg); | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "psycopg/connection.h" | #include "psycopg/connection.h" | ||||||
| #include "psycopg/cursor.h" | #include "psycopg/cursor.h" | ||||||
|  | #include "psycopg/replication_message.h" | ||||||
| #include "psycopg/green.h" | #include "psycopg/green.h" | ||||||
| #include "psycopg/lobject.h" | #include "psycopg/lobject.h" | ||||||
| #include "psycopg/notify.h" | #include "psycopg/notify.h" | ||||||
|  | @ -785,6 +786,9 @@ INIT_MODULE(_psycopg)(void) | ||||||
|     Py_TYPE(&cursorType) = &PyType_Type; |     Py_TYPE(&cursorType) = &PyType_Type; | ||||||
|     if (PyType_Ready(&cursorType) == -1) goto exit; |     if (PyType_Ready(&cursorType) == -1) goto exit; | ||||||
| 
 | 
 | ||||||
|  |     Py_TYPE(&replicationMessageType) = &PyType_Type; | ||||||
|  |     if (PyType_Ready(&replicationMessageType) == -1) goto exit; | ||||||
|  | 
 | ||||||
|     Py_TYPE(&typecastType) = &PyType_Type; |     Py_TYPE(&typecastType) = &PyType_Type; | ||||||
|     if (PyType_Ready(&typecastType) == -1) goto exit; |     if (PyType_Ready(&typecastType) == -1) goto exit; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										52
									
								
								psycopg/replication_message.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								psycopg/replication_message.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | /* replication_message.h - definition for the psycopg ReplicationMessage type
 | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2003-2015 Federico Di Gregorio <fog@debian.org> | ||||||
|  |  * | ||||||
|  |  * This file is part of psycopg. | ||||||
|  |  * | ||||||
|  |  * psycopg2 is free software: you can redistribute it and/or modify it | ||||||
|  |  * under the terms of the GNU Lesser General Public License as published | ||||||
|  |  * by the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * In addition, as a special exception, the copyright holders give | ||||||
|  |  * permission to link this program with the OpenSSL library (or with | ||||||
|  |  * modified versions of OpenSSL that use the same license as OpenSSL), | ||||||
|  |  * and distribute linked combinations including the two. | ||||||
|  |  * | ||||||
|  |  * You must obey the GNU Lesser General Public License in all respects for | ||||||
|  |  * all of the code used other than OpenSSL. | ||||||
|  |  * | ||||||
|  |  * psycopg2 is distributed in the hope that it will be useful, but WITHOUT | ||||||
|  |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public | ||||||
|  |  * License for more details. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef PSYCOPG_REPLICATION_MESSAGE_H | ||||||
|  | #define PSYCOPG_REPLICATION_MESSAGE_H 1 | ||||||
|  | 
 | ||||||
|  | #include "libpq_support.h" | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | extern HIDDEN PyTypeObject replicationMessageType; | ||||||
|  | 
 | ||||||
|  | /* the typedef is forward-declared in psycopg.h */ | ||||||
|  | struct replicationMessageObject { | ||||||
|  |     PyObject_HEAD | ||||||
|  | 
 | ||||||
|  |     PyObject *payload; | ||||||
|  | 
 | ||||||
|  |     XLogRecPtr  data_start; | ||||||
|  |     XLogRecPtr  wal_end; | ||||||
|  |     /* send_time */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif /* !defined(PSYCOPG_REPLICATION_MESSAGE_H) */ | ||||||
							
								
								
									
										127
									
								
								psycopg/replication_message_type.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								psycopg/replication_message_type.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,127 @@ | ||||||
|  | /* replication_message_type.c - python interface to ReplcationMessage objects
 | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2003-2015 Federico Di Gregorio <fog@debian.org> | ||||||
|  |  * | ||||||
|  |  * This file is part of psycopg. | ||||||
|  |  * | ||||||
|  |  * psycopg2 is free software: you can redistribute it and/or modify it | ||||||
|  |  * under the terms of the GNU Lesser General Public License as published | ||||||
|  |  * by the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * In addition, as a special exception, the copyright holders give | ||||||
|  |  * permission to link this program with the OpenSSL library (or with | ||||||
|  |  * modified versions of OpenSSL that use the same license as OpenSSL), | ||||||
|  |  * and distribute linked combinations including the two. | ||||||
|  |  * | ||||||
|  |  * You must obey the GNU Lesser General Public License in all respects for | ||||||
|  |  * all of the code used other than OpenSSL. | ||||||
|  |  * | ||||||
|  |  * psycopg2 is distributed in the hope that it will be useful, but WITHOUT | ||||||
|  |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public | ||||||
|  |  * License for more details. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define PSYCOPG_MODULE | ||||||
|  | #include "psycopg/psycopg.h" | ||||||
|  | 
 | ||||||
|  | #include "psycopg/replication_message.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | replmsg_repr(replicationMessageObject *self) | ||||||
|  | { | ||||||
|  |     return PyString_FromFormat( | ||||||
|  |         "<replicationMessage object at %p; data_start: "XLOGFMTSTR"; wal_end: "XLOGFMTSTR">", | ||||||
|  |         self, XLOGFMTARGS(self->data_start), XLOGFMTARGS(self->wal_end)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | replmsg_init(PyObject *obj, PyObject *args, PyObject *kwargs) | ||||||
|  | { | ||||||
|  |     replicationMessageObject *self = (replicationMessageObject*) obj; | ||||||
|  | 
 | ||||||
|  |     if (!PyArg_ParseTuple(args, "O", &self->payload)) | ||||||
|  |         return -1; | ||||||
|  |     Py_XINCREF(self->payload); | ||||||
|  | 
 | ||||||
|  |     self->data_start = 0; | ||||||
|  |     self->wal_end = 0; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | replmsg_clear(PyObject *self) | ||||||
|  | { | ||||||
|  |     Py_CLEAR(((replicationMessageObject*) self)->payload); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | replmsg_dealloc(PyObject* obj) | ||||||
|  | { | ||||||
|  |     replmsg_clear(obj); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #define OFFSETOF(x) offsetof(replicationMessageObject, x) | ||||||
|  | 
 | ||||||
|  | /* object member list */ | ||||||
|  | 
 | ||||||
|  | static struct PyMemberDef replicationMessageObject_members[] = { | ||||||
|  |     {"payload", T_OBJECT, OFFSETOF(payload), READONLY, | ||||||
|  |         "TODO"}, | ||||||
|  |     {"data_start", T_ULONGLONG, OFFSETOF(data_start), READONLY, | ||||||
|  |         "TODO"}, | ||||||
|  |     {"wal_end", T_ULONGLONG, OFFSETOF(wal_end), READONLY, | ||||||
|  |         "TODO"}, | ||||||
|  |     {NULL} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* object type */ | ||||||
|  | 
 | ||||||
|  | #define replicationMessageType_doc \ | ||||||
|  | "A database replication message." | ||||||
|  | 
 | ||||||
|  | PyTypeObject replicationMessageType = { | ||||||
|  |     PyVarObject_HEAD_INIT(NULL, 0) | ||||||
|  |     "psycopg2.extensions.ReplicationMessage", | ||||||
|  |     sizeof(replicationMessageObject), 0, | ||||||
|  |     replmsg_dealloc, /*tp_dealloc*/ | ||||||
|  |     0,          /*tp_print*/ | ||||||
|  |     0,          /*tp_getattr*/ | ||||||
|  |     0,          /*tp_setattr*/ | ||||||
|  |     0,          /*tp_compare*/ | ||||||
|  |     (reprfunc)replmsg_repr, /*tp_repr*/ | ||||||
|  |     0,          /*tp_as_number*/ | ||||||
|  |     0,          /*tp_as_sequence*/ | ||||||
|  |     0,          /*tp_as_mapping*/ | ||||||
|  |     0,          /*tp_hash */ | ||||||
|  |     0,          /*tp_call*/ | ||||||
|  |     0,          /*tp_str*/ | ||||||
|  |     0,          /*tp_getattro*/ | ||||||
|  |     0,          /*tp_setattro*/ | ||||||
|  |     0,          /*tp_as_buffer*/ | ||||||
|  |     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, | ||||||
|  |                 /*tp_flags*/ | ||||||
|  |     replicationMessageType_doc, /*tp_doc*/ | ||||||
|  |     0,          /*tp_traverse*/ | ||||||
|  |     replmsg_clear, /*tp_clear*/ | ||||||
|  |     0,          /*tp_richcompare*/ | ||||||
|  |     0, /*tp_weaklistoffset*/ | ||||||
|  |     0, /*tp_iter*/ | ||||||
|  |     0, /*tp_iternext*/ | ||||||
|  |     0, /*tp_methods*/ | ||||||
|  |     replicationMessageObject_members, /*tp_members*/ | ||||||
|  |     0, /*tp_getset*/ | ||||||
|  |     0, /*tp_base*/ | ||||||
|  |     0,          /*tp_dict*/ | ||||||
|  |     0,          /*tp_descr_get*/ | ||||||
|  |     0,          /*tp_descr_set*/ | ||||||
|  |     0,          /*tp_dictoffset*/ | ||||||
|  |     replmsg_init, /*tp_init*/ | ||||||
|  |     0,          /*tp_alloc*/ | ||||||
|  |     PyType_GenericNew, /*tp_new*/ | ||||||
|  | }; | ||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -466,6 +466,7 @@ sources = [ | ||||||
| 
 | 
 | ||||||
|     'connection_int.c', 'connection_type.c', |     'connection_int.c', 'connection_type.c', | ||||||
|     'cursor_int.c', 'cursor_type.c', |     'cursor_int.c', 'cursor_type.c', | ||||||
|  |     'replication_message_type.c', | ||||||
|     'diagnostics_type.c', 'error_type.c', |     'diagnostics_type.c', 'error_type.c', | ||||||
|     'lobject_int.c', 'lobject_type.c', |     'lobject_int.c', 'lobject_type.c', | ||||||
|     'notify_type.c', 'xid_type.c', |     'notify_type.c', 'xid_type.c', | ||||||
|  | @ -481,6 +482,7 @@ depends = [ | ||||||
|     # headers |     # headers | ||||||
|     'config.h', 'pgtypes.h', 'psycopg.h', 'python.h', 'connection.h', |     'config.h', 'pgtypes.h', 'psycopg.h', 'python.h', 'connection.h', | ||||||
|     'cursor.h', 'diagnostics.h', 'error.h', 'green.h', 'lobject.h', |     'cursor.h', 'diagnostics.h', 'error.h', 'green.h', 'lobject.h', | ||||||
|  |     'replication_message.h', | ||||||
|     'notify.h', 'pqpath.h', 'xid.h', |     'notify.h', 'pqpath.h', 'xid.h', | ||||||
|     'libpq_support.h', 'win32_support.h', |     'libpq_support.h', 'win32_support.h', | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user