12
12
*
13
13
*
14
14
* IDENTIFICATION
15
- * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.9 1998/05/06 23:51:00 momjian Exp $
15
+ * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.10 1998/05/06 23:53:30 momjian Exp $
16
16
*
17
17
*-------------------------------------------------------------------------
18
18
*/
@@ -60,19 +60,21 @@ int PgInputProc(DRIVER_INPUT_PROTO)
60
60
return -1 ;
61
61
}
62
62
63
- if (connid -> res_copyStatus == RES_COPY_FIN ) {
64
- return PgEndCopy (connid , errorCodePtr );
65
- }
66
-
67
63
/* Try to load any newly arrived data */
68
64
errno = 0 ;
69
65
70
66
if (pqReadData (conn ) < 0 ) {
71
- * errorCodePtr = errno ? errno : EIO ;
72
- return -1 ;
67
+ * errorCodePtr = errno ? errno : EIO ;
68
+ return -1 ;
73
69
}
74
70
75
- /* Move data from libpq's buffer to tcl's */
71
+ /* Move data from libpq's buffer to Tcl's.
72
+ * We want to accept data only in units of whole lines,
73
+ * not partial lines. This ensures that we can recognize
74
+ * the terminator line "\\.\n". (Otherwise, if it happened
75
+ * to cross a packet/buffer boundary, we might hand the first
76
+ * one or two characters off to Tcl, which we shouldn't.)
77
+ */
76
78
77
79
conn -> inCursor = conn -> inStart ;
78
80
@@ -81,19 +83,33 @@ int PgInputProc(DRIVER_INPUT_PROTO)
81
83
pqGetc (& c , conn ) == 0 ) {
82
84
* buf ++ = c ;
83
85
-- avail ;
84
- if (c == '\n' && bufSize - avail >= 3 ) {
85
- if ((bufSize - avail == 3 || buf [-4 ] == '\n' ) &&
86
- buf [-3 ] == '\\' && buf [-2 ] == '.' ) {
87
- avail += 3 ;
88
- connid -> res_copyStatus = RES_COPY_FIN ;
89
- break ;
86
+ if (c == '\n' ) {
87
+ /* Got a complete line; mark the data removed from libpq */
88
+ conn -> inStart = conn -> inCursor ;
89
+ /* Is it the endmarker line? */
90
+ if (bufSize - avail == 3 && buf [-3 ] == '\\' && buf [-2 ] == '.' ) {
91
+ /* Yes, change state and return 0 */
92
+ return PgEndCopy (connid , errorCodePtr );
90
93
}
94
+ /* No, return the data to Tcl */
95
+ /* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
96
+ return bufSize - avail ;
91
97
}
92
98
}
93
- /* Accept the data permanently */
94
- conn -> inStart = conn -> inCursor ;
95
- /* fprintf(stderr, "returning %d chars\n", bufSize - avail); */
96
- return bufSize - avail ;
99
+
100
+ /* We don't have a complete line.
101
+ * We'd prefer to leave it in libpq's buffer until the rest arrives,
102
+ * but there is a special case: what if the line is longer than the
103
+ * buffer Tcl is offering us? In that case we'd better hand over
104
+ * a partial line, else we'd get into an infinite loop.
105
+ * Do this in a way that ensures we can't misrecognize a terminator
106
+ * line later: leave last 3 characters in libpq buffer.
107
+ */
108
+ if (avail == 0 && bufSize > 3 ) {
109
+ conn -> inStart = conn -> inCursor - 3 ;
110
+ return bufSize - 3 ;
111
+ }
112
+ return 0 ;
97
113
}
98
114
99
115
/*
@@ -116,10 +132,13 @@ int PgOutputProc(DRIVER_OUTPUT_PROTO)
116
132
errno = 0 ;
117
133
118
134
if (pqPutnchar (buf , bufSize , conn )) {
119
- * errorCodePtr = errno ? errno : EIO ;
120
- return -1 ;
135
+ * errorCodePtr = errno ? errno : EIO ;
136
+ return -1 ;
121
137
}
122
138
139
+ /* This assumes Tcl script will write the terminator line
140
+ * in a single operation; maybe not such a good assumption?
141
+ */
123
142
if (bufSize >= 3 && strncmp (& buf [bufSize - 3 ], "\\.\n" , 3 ) == 0 ) {
124
143
(void ) pqFlush (conn );
125
144
if (PgEndCopy (connid , errorCodePtr ) == -1 )
0 commit comments