<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"> <title>FreeTDS API: /usr/local/users/home/jklowden/projects/releases/freetds/0.82/src/dblib/buffering.h Source File</title> <link href="doxygen.css" rel="stylesheet" type="text/css"> </head><body> <!-- Generated by Doxygen 1.4.1 --> <div class="qindex"><a class="qindex" href="index.html">Main Page</a> | <a class="qindex" href="modules.html">Modules</a> | <a class="qindex" href="annotated.html">Class List</a> | <a class="qindex" href="dirs.html">Directories</a> | <a class="qindex" href="files.html">File List</a> | <a class="qindex" href="functions.html">Class Members</a> | <a class="qindex" href="globals.html">File Members</a> | <a class="qindex" href="pages.html">Related Pages</a></div> <div class="nav"> <a class="el" href="dir_000002.html">src</a> / <a class="el" href="dir_000006.html">dblib</a></div> <h1>buffering.h</h1><div class="fragment"><pre class="fragment">00001 <span class="keyword">typedef</span> <span class="keyword">struct </span>dblib_buffer_row { 00003 <a class="code" href="a00143.html">TDSRESULTINFO</a> *resinfo; 00005 <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> *row_data; 00007 DBINT row; 00009 TDS_INT *sizes; 00010 } DBLIB_BUFFER_ROW; 00011 00012 <span class="keyword">static</span> <span class="keywordtype">void</span> buffer_struct_print(<span class="keyword">const</span> DBPROC_ROWBUF *buf); 00013 <span class="keyword">static</span> <span class="keywordtype">int</span> buffer_save_row(DBPROCESS *dbproc); 00014 <span class="keyword">static</span> DBLIB_BUFFER_ROW* buffer_row_address(<span class="keyword">const</span> DBPROC_ROWBUF * buf, <span class="keywordtype">int</span> idx); 00015 00045 <span class="keyword">static</span> <span class="keywordtype">int</span> 00046 buffer_count(<span class="keyword">const</span> DBPROC_ROWBUF *buf) 00047 { 00048 <span class="keywordflow">return</span> (buf->head > buf->tail) ? 00049 buf->head - buf->tail : <span class="comment">/* |...TddddH....| */</span> 00050 buf->capacity - (buf->tail - buf->head); <span class="comment">/* |ddddH....Tddd| */</span> 00051 } 00052 00056 <span class="keyword">static</span> <span class="keywordtype">int</span> 00057 buffer_is_full(<span class="keyword">const</span> DBPROC_ROWBUF *buf) 00058 { 00059 <span class="keywordflow">return</span> buf->capacity == buffer_count(buf) && buf->capacity > 1; 00060 } 00061 00062 <span class="preprocessor">#ifndef NDEBUG</span> 00063 <span class="preprocessor"></span><span class="keyword">static</span> <span class="keywordtype">int</span> 00064 buffer_index_valid(<span class="keyword">const</span> DBPROC_ROWBUF *buf, <span class="keywordtype">int</span> idx) 00065 { 00066 <span class="keywordflow">if</span> (buf->tail <= buf->head) 00067 if (buf->head <= idx && idx <= buf->tail) 00068 return 1; 00069 00070 if (0 <= idx && idx <= buf->head) 00071 return 1; 00072 00073 if (buf->tail <= idx && idx < buf->capacity) 00074 return 1; 00075 #if 0 00076 printf("buffer_index_valid: idx = %d\n", idx); 00077 buffer_struct_print(buf); 00078 #endif 00079 return 0; 00080 } 00081 #endif 00082 00083 static <span class="keywordtype">void</span> 00084 buffer_free_row(DBLIB_BUFFER_ROW *row) 00085 { 00086 <span class="keywordflow">if</span> (row->sizes) 00087 TDS_ZERO_FREE(row->sizes); 00088 if (row->row_data) { 00089 tds_free_row(row->resinfo, row->row_data); 00090 row->row_data = NULL; 00091 } 00092 tds_free_results(row->resinfo); 00093 row->resinfo = NULL; 00094 } 00095 00096 <span class="comment">/*</span> 00097 <span class="comment"> * Buffer is freed at slightly odd points, whenever</span> 00098 <span class="comment"> * capacity changes: </span> 00099 <span class="comment"> * </span> 00100 <span class="comment"> * 1. When setting capacity, to release prior buffer. </span> 00101 <span class="comment"> * 2. By dbresults. When called the second time, it has to </span> 00102 <span class="comment"> * release prior storage because the new resultset will have</span> 00103 <span class="comment"> * a different width. </span> 00104 <span class="comment"> * 3. By dbclose(), else open/close/open would leak. </span> 00105 <span class="comment"> */</span> 00106 <span class="keyword">static</span> <span class="keywordtype">void</span> 00107 buffer_free(DBPROC_ROWBUF *buf) 00108 { 00109 <span class="keywordflow">if</span> (buf->rows != NULL) { 00110 <span class="keywordtype">int</span> i; 00111 <span class="keywordflow">for</span> (i = 0; i < buf->capacity; ++i) 00112 buffer_free_row(&buf->rows[i]); 00113 TDS_ZERO_FREE(buf->rows); 00114 } 00115 } 00116 00117 <span class="comment">/*</span> 00118 <span class="comment"> * When no rows are currently buffered (and the buffer is allocated)</span> 00119 <span class="comment"> * set the indices to their initial postions.</span> 00120 <span class="comment"> */</span> 00121 static <span class="keywordtype">void</span> 00122 buffer_reset(DBPROC_ROWBUF *buf) 00123 { 00124 buf->head = 0; 00125 buf->current = buf->tail = buf->capacity; 00126 } 00127 00128 <span class="keyword">static</span> <span class="keywordtype">int</span> 00129 buffer_idx_increment(<span class="keyword">const</span> DBPROC_ROWBUF *buf, <span class="keywordtype">int</span> idx) 00130 { 00131 <span class="keywordflow">if</span> (++idx >= buf->capacity) { 00132 idx = 0; 00133 } 00134 <span class="keywordflow">return</span> idx; 00135 } 00136 00141 <span class="keyword">static</span> DBLIB_BUFFER_ROW* 00142 buffer_row_address(<span class="keyword">const</span> DBPROC_ROWBUF * buf, <span class="keywordtype">int</span> idx) 00143 { 00144 <span class="keywordflow">if</span> (!(idx >= 0 && idx < buf->capacity)) { 00145 printf(<span class="stringliteral">"idx is %d:\n"</span>, idx); 00146 buffer_struct_print(buf); 00147 assert(idx >= 0); 00148 assert(idx < buf->capacity); 00149 } 00150 00151 <span class="keywordflow">return</span> &(buf->rows[idx]); 00152 } 00153 00157 <span class="keyword">static</span> DBINT 00158 buffer_idx2row(<span class="keyword">const</span> DBPROC_ROWBUF *buf, <span class="keywordtype">int</span> idx) 00159 { 00160 <span class="keywordflow">return</span> buffer_row_address(buf, idx)->row; 00161 } 00162 00166 <span class="keyword">static</span> <span class="keywordtype">int</span> 00167 buffer_row2idx(<span class="keyword">const</span> DBPROC_ROWBUF *buf, <span class="keywordtype">int</span> row_number) 00168 { 00169 <span class="keywordtype">int</span> i, ii, idx = -1; 00170 00171 <span class="keywordflow">if</span> (buf->tail == buf->capacity) { 00172 assert (buf->head == 0); 00173 <span class="keywordflow">return</span> -1; <span class="comment">/* no rows buffered */</span> 00174 } 00175 00176 <span class="comment">/* </span> 00177 <span class="comment"> * March through the buffers from tail to head, stop if we find our row. </span> 00178 <span class="comment"> * A full queue is indicated by tail == head (which means we can't write).</span> 00179 <span class="comment"> */</span> 00180 <span class="keywordflow">for</span> (ii=0, i = buf->tail; i != buf->head || ii == 0; i = buffer_idx_increment(buf, i)) { 00181 <span class="keywordflow">if</span>( buffer_idx2row(buf, i) == row_number) { 00182 idx = i; 00183 <span class="keywordflow">break</span>; 00184 } 00185 assert(ii++ < buf->capacity); <span class="comment">/* prevent infinite loop */</span> 00186 } 00187 00188 <span class="keywordflow">return</span> idx; 00189 } 00190 00196 <span class="keyword">static</span> <span class="keywordtype">void</span> 00197 buffer_delete_rows(DBPROC_ROWBUF * buf, <span class="keywordtype">int</span> count) 00198 { 00199 <span class="keywordtype">int</span> i; 00200 00201 <span class="keywordflow">if</span> (count < 0 || count > buffer_count(buf)) { 00202 count = buffer_count(buf); 00203 } 00204 00205 <span class="keywordflow">for</span> (i=0; i < count; i++) { 00206 <span class="keywordflow">if</span> (buf->tail < buf->capacity) 00207 buffer_free_row(&buf->rows[i]); 00208 buf->tail = buffer_idx_increment(buf, buf->tail); 00209 <span class="comment">/* </span> 00210 <span class="comment"> * If deleting rows from the buffer catches the tail to the head, </span> 00211 <span class="comment"> * return to the initial postion. Otherwise, it will look full.</span> 00212 <span class="comment"> */</span> 00213 if (buf->tail == buf->head) { 00214 buffer_reset(buf); 00215 <span class="keywordflow">break</span>; 00216 } 00217 } 00218 <span class="preprocessor">#if 0</span> 00219 <span class="preprocessor"></span> buffer_struct_print(buf); 00220 <span class="preprocessor">#endif</span> 00221 <span class="preprocessor"></span>} 00222 00223 <span class="keyword">static</span> <span class="keywordtype">void</span> 00224 buffer_transfer_bound_data(DBPROC_ROWBUF *buf, TDS_INT res_type, TDS_INT compute_id, DBPROCESS * dbproc, <span class="keywordtype">int</span> idx) 00225 { 00226 <span class="keywordtype">int</span> i; 00227 <span class="keywordtype">int</span> srctype, desttype; 00228 BYTE *src; 00229 <span class="keyword">const</span> DBLIB_BUFFER_ROW *row; 00230 00231 tdsdump_log(TDS_DBG_FUNC, <span class="stringliteral">"buffer_transfer_bound_data(%p %d %d %p %d)\n"</span>, buf, res_type, compute_id, dbproc, idx); 00232 assert(buffer_index_valid(buf, idx)); 00233 00234 row = buffer_row_address(buf, idx); 00235 assert(row->resinfo); 00236 00237 <span class="keywordflow">for</span> (i = 0; i < row->resinfo->num_cols; i++) { 00238 DBINT srclen; 00239 <a class="code" href="a00140.html">TDSCOLUMN</a> *curcol = row->resinfo->columns[i]; 00240 00241 <span class="keywordflow">if</span> (row->sizes) 00242 curcol->column_cur_size = row->sizes[i]; 00243 00244 if (curcol->column_nullbind) { 00245 <span class="keywordflow">if</span> (curcol-><a class="code" href="a00140.html#o9">column_cur_size</a> < 0) { 00246 *(DBINT *)(curcol-><a class="code" href="a00140.html#o20">column_nullbind</a>) = -1; 00247 } <span class="keywordflow">else</span> { 00248 *(DBINT *)(curcol-><a class="code" href="a00140.html#o20">column_nullbind</a>) = 0; 00249 } 00250 } 00251 <span class="keywordflow">if</span> (!curcol-><a class="code" href="a00140.html#o32">column_varaddr</a>) 00252 continue; 00253 00254 if (row->row_data) 00255 src = &row->row_data[curcol->column_data - row->resinfo->current_row]; 00256 else 00257 src = curcol->column_data; 00258 srclen = curcol->column_cur_size; 00259 if (is_blob_type(curcol->column_type)) { 00260 src = (BYTE *) ((<a class="code" href="a00139.html">TDSBLOB</a> *) src)->textvalue; 00261 } 00262 desttype = _db_get_server_type(curcol-><a class="code" href="a00140.html#o7">column_bindtype</a>); 00263 srctype = <a class="code" href="a00287.html#ga17">tds_get_conversion_type</a>(curcol-><a class="code" href="a00140.html#o30">column_type</a>, curcol-><a class="code" href="a00140.html#o26">column_size</a>); 00264 00265 <span class="keywordflow">if</span> (srclen <= 0) { 00266 <span class="keywordflow">if</span> (srclen == 0 || !curcol-><a class="code" href="a00140.html#o20">column_nullbind</a>) 00267 dbgetnull(dbproc, curcol->column_bindtype, curcol->column_bindlen, 00268 (BYTE *) curcol->column_varaddr); 00269 } else { 00270 copy_data_to_host_var(dbproc, srctype, src, srclen, desttype, 00271 (BYTE *) curcol-><a class="code" href="a00140.html#o32">column_varaddr</a>, curcol-><a class="code" href="a00140.html#o6">column_bindlen</a>, 00272 curcol-><a class="code" href="a00140.html#o7">column_bindtype</a>, curcol-><a class="code" href="a00140.html#o20">column_nullbind</a>); 00273 } 00274 } 00275 00276 <span class="comment">/*</span> 00277 <span class="comment"> * This function always bumps current. Usually, it's called </span> 00278 <span class="comment"> * by dbnextrow(), so bumping current is a pretty obvious choice. </span> 00279 <span class="comment"> * It can also be called by dbgetrow(), but that function also </span> 00280 <span class="comment"> * causes the bump. If you call dbgetrow() for row N, a subsequent</span> 00281 <span class="comment"> * call to dbnextrow() yields N+1. </span> 00282 <span class="comment"> */</span> 00283 buf->current = buffer_idx_increment(buf, buf->current); 00284 00285 } <span class="comment">/* end buffer_transfer_bound_data() */</span> 00286 00287 <span class="keyword">static</span> <span class="keywordtype">void</span> 00288 buffer_struct_print(<span class="keyword">const</span> DBPROC_ROWBUF *buf) 00289 { 00290 assert(buf); 00291 00292 printf(<span class="stringliteral">"\t%d rows in buffer\n"</span>, buffer_count(buf)); 00293 00294 printf(<span class="stringliteral">"\thead = %d\t"</span>, buf->head); 00295 printf(<span class="stringliteral">"\ttail = %d\t"</span>, buf->tail); 00296 printf(<span class="stringliteral">"\tcurrent = %d\n"</span>, buf->current); 00297 printf(<span class="stringliteral">"\tcapacity = %d\t"</span>, buf->capacity); 00298 printf(<span class="stringliteral">"\thead row number = %d\n"</span>, buf->received); 00299 } 00300 00301 <span class="comment">/* * * Functions called only by public db-lib API take DBPROCESS* * */</span> 00302 00319 <span class="keyword">static</span> <span class="keywordtype">int</span> 00320 buffer_current_index(<span class="keyword">const</span> DBPROCESS *dbproc) 00321 { 00322 <span class="keyword">const</span> DBPROC_ROWBUF *buf = &dbproc->row_buf; 00323 <span class="preprocessor">#if 0</span> 00324 <span class="preprocessor"></span> buffer_struct_print(buf); 00325 <span class="preprocessor">#endif</span> 00326 <span class="preprocessor"></span> <span class="keywordflow">if</span> (buf->capacity <= 1) <span class="comment">/* no buffering */</span> 00327 return -1; 00328 if (buf->current == buf->head || buf->current == buf->capacity) 00329 return -1; 00330 00331 assert(buf->current >= 0); 00332 assert(buf->current < buf->capacity); 00333 00334 if( buf->tail < buf->head) { 00335 assert(buf->tail < buf->current); 00336 assert(buf->current < buf->head); 00337 } <span class="keywordflow">else</span> { 00338 <span class="keywordflow">if</span> (buf->current > buf->head) 00339 assert(buf->current > buf->tail); 00340 } 00341 return buf->current; 00342 } 00343 00344 <span class="comment">/*</span> 00345 <span class="comment"> * Normally called by dbsetopt() to prepare for buffering</span> 00346 <span class="comment"> * Called with nrows == 0 by dbopen to safely set buf->rows to NULL. </span> 00347 <span class="comment"> */</span> 00348 static <span class="keywordtype">void</span> 00349 buffer_set_capacity(DBPROCESS *dbproc, <span class="keywordtype">int</span> nrows) 00350 { 00351 DBPROC_ROWBUF *buf = &dbproc->row_buf; 00352 00353 buffer_free(buf); 00354 00355 memset(buf, 0, <span class="keyword">sizeof</span>(DBPROC_ROWBUF)); 00356 00357 <span class="keywordflow">if</span> (0 == nrows) { 00358 buf->capacity = 1; 00359 <span class="keywordflow">return</span>; 00360 } 00361 00362 assert(0 < nrows); 00363 00364 buf->capacity = nrows; 00365 } 00366 00367 <span class="comment">/*</span> 00368 <span class="comment"> * Called only by dbresults(); capacity must be >= 1. </span> 00369 <span class="comment"> * Sybase's documents say dbresults() cannot return FAIL if the prior calls worked, </span> 00370 <span class="comment"> * which is a little strange, because (for FreeTDS, at least), dbresults</span> 00371 <span class="comment"> * is when we learn about the result set's width. Without that information, we</span> 00372 <span class="comment"> * can't allocate memory for the buffer. But if we *fail* to allocate memory, </span> 00373 <span class="comment"> * we're not to communicate it back to the caller? </span> 00374 <span class="comment"> */</span> 00375 <span class="keyword">static</span> <span class="keywordtype">void</span> 00376 buffer_alloc(DBPROCESS *dbproc) 00377 { 00378 DBPROC_ROWBUF *buf = &dbproc->row_buf; 00379 00380 <span class="comment">/* Call this function only after setting capacity. */</span> 00381 00382 assert(buf); 00383 assert(buf->capacity > 0); 00384 assert(buf->rows == NULL); 00385 00386 buf->rows = (DBLIB_BUFFER_ROW *) calloc(buf->capacity, <span class="keyword">sizeof</span>(DBLIB_BUFFER_ROW)); 00387 00388 assert(buf->rows); 00389 00390 buffer_reset(buf); 00391 00392 buf->received = 0; 00393 } 00394 00399 <span class="keyword">static</span> <span class="keywordtype">int</span> 00400 buffer_add_row(DBPROCESS *dbproc, <a class="code" href="a00143.html">TDSRESULTINFO</a> *resinfo) 00401 { 00402 DBPROC_ROWBUF *buf = &dbproc->row_buf; 00403 DBLIB_BUFFER_ROW *row; 00404 <span class="keywordtype">int</span> i; 00405 00406 assert(buf->capacity >= 0); 00407 00408 <span class="keywordflow">if</span> (buffer_is_full(buf)) 00409 return -1; 00410 00411 <span class="comment">/* initial condition is head == 0 and tail == capacity */</span> 00412 if (buf->tail == buf->capacity) { 00413 <span class="comment">/* bumping this tail will set it to zero */</span> 00414 assert(buf->head == 0); 00415 buf->tail = buffer_idx_increment(buf, buf->tail); 00416 } 00417 00418 row = buffer_row_address(buf, buf->head); 00419 00420 <span class="comment">/* bump the row number, write it, and move the data to head */</span> 00421 <span class="keywordflow">if</span> (row->resinfo) { 00422 tds_free_row(row->resinfo, row->row_data); 00423 tds_free_results(row->resinfo); 00424 } 00425 row->row = ++buf->received; 00426 ++resinfo->ref_count; 00427 row->resinfo = resinfo; 00428 row->row_data = NULL; 00429 <span class="keywordflow">if</span> (row->sizes) 00430 free(row->sizes); 00431 row->sizes = (TDS_INT *) calloc(resinfo->num_cols, sizeof(TDS_INT)); 00432 for (i = 0; i < resinfo->num_cols; ++i) 00433 row->sizes[i] = resinfo->columns[i]->column_cur_size; 00434 00435 <span class="comment">/* update current, bump the head */</span> 00436 buf->current = buf->head; 00437 buf->head = buffer_idx_increment(buf, buf->head); 00438 00439 return buf->current; 00440 } 00441 00442 static <span class="keywordtype">int</span> 00443 buffer_save_row(DBPROCESS *dbproc) 00444 { 00445 DBPROC_ROWBUF *buf = &dbproc->row_buf; 00446 DBLIB_BUFFER_ROW *row; 00447 <span class="keywordtype">int</span> idx = buf->head - 1; 00448 00449 <span class="keywordflow">if</span> (buf->capacity <= 1) 00450 return SUCCEED; 00451 00452 if (idx < 0) 00453 idx = buf->capacity - 1; 00454 if (idx >= 0 && idx < buf->capacity) { 00455 row = &buf->rows[idx]; 00456 00457 <span class="keywordflow">if</span> (row->resinfo && !row->row_data) { 00458 row->row_data = row->resinfo->current_row; 00459 <a class="code" href="a00289.html#ga12">tds_alloc_row</a>(row->resinfo); 00460 } 00461 } 00462 00463 <span class="keywordflow">return</span> SUCCEED; 00464 } 00465 </pre></div><hr size="1"><address style="align: right;"><small>Generated on Wed May 7 19:22:09 2008 for FreeTDS API by <a href="http://www.doxygen.org/index.html"> <img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.4.1 </small></address> </body> </html>