Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * This code was created by Peter Harvey (mostly during Christmas 98/99).
15 : * This code is LGPL. Please ensure that this message remains in future
16 : * distributions and uses of this code (thats about all I get out of it).
17 : * - Peter Harvey pharvey@codebydesign.com
18 : *
19 : * This file has been modified for the MonetDB project. See the file
20 : * Copyright in this directory for more information.
21 : */
22 :
23 : /*****************************************************************************
24 : * SQLFetchScroll()
25 : * CLI Compliance: ISO 92
26 : *
27 : * Author: Martin van Dinther, Sjoerd Mullender
28 : * Date : 30 aug 2002
29 : *
30 : *****************************************************************************/
31 :
32 : #include "ODBCGlobal.h"
33 : #include "ODBCStmt.h"
34 :
35 :
36 : SQLRETURN
37 1001 : MNDBFetchScroll(ODBCStmt *stmt,
38 : SQLSMALLINT FetchOrientation,
39 : SQLLEN FetchOffset,
40 : SQLUSMALLINT *RowStatusArray)
41 : {
42 1001 : assert(stmt->hdl);
43 :
44 1001 : if ((stmt->cursorType == SQL_CURSOR_FORWARD_ONLY ||
45 1001 : stmt->cursorScrollable == SQL_NONSCROLLABLE) &&
46 : FetchOrientation != SQL_FETCH_NEXT) {
47 : /* Fetch type out of range */
48 0 : addStmtError(stmt, "HY106", NULL, 0);
49 0 : return SQL_ERROR;
50 : }
51 : #define RowSetSize (stmt->ApplRowDescr->sql_desc_array_size)
52 :
53 1001 : assert(stmt->startRow >= 0);
54 1001 : switch (FetchOrientation) {
55 1001 : case SQL_FETCH_NEXT:
56 1001 : stmt->startRow += stmt->rowSetSize;
57 1001 : break;
58 0 : case SQL_FETCH_FIRST:
59 0 : stmt->startRow = 0;
60 0 : break;
61 0 : case SQL_FETCH_LAST:
62 0 : if (stmt->rowcount < RowSetSize)
63 0 : stmt->startRow = 0;
64 : else
65 0 : stmt->startRow = stmt->rowcount - RowSetSize;
66 : break;
67 0 : case SQL_FETCH_PRIOR:
68 0 : if (stmt->startRow == 0) {
69 : /* before start */
70 0 : stmt->startRow = 0;
71 0 : stmt->rowSetSize = 0;
72 0 : stmt->State = FETCHED;
73 0 : return SQL_NO_DATA;
74 : }
75 0 : if (stmt->startRow < (SQLLEN) RowSetSize) {
76 : /* Attempt to fetch before the result set
77 : * returned the first rowset */
78 0 : addStmtError(stmt, "01S06", NULL, 0);
79 0 : stmt->startRow = 0;
80 : } else
81 0 : stmt->startRow = stmt->startRow - RowSetSize;
82 : break;
83 0 : case SQL_FETCH_RELATIVE:
84 0 : if ((stmt->startRow > 0 || stmt->rowSetSize > 0 ||
85 0 : FetchOffset <= 0) &&
86 0 : ((SQLULEN) stmt->startRow < stmt->rowcount ||
87 : FetchOffset >= 0)) {
88 0 : if ((stmt->startRow == 0 && stmt->rowSetSize == 0 &&
89 0 : FetchOffset <= 0) ||
90 0 : (stmt->startRow == 0 && stmt->rowSetSize > 0 &&
91 0 : FetchOffset < 0) ||
92 0 : (stmt->startRow > 0 &&
93 0 : stmt->startRow + FetchOffset < 1 &&
94 0 : (FetchOffset > (SQLLEN) RowSetSize ||
95 0 : -FetchOffset > (SQLLEN) RowSetSize))) {
96 : /* before start */
97 0 : stmt->startRow = 0;
98 0 : stmt->rowSetSize = 0;
99 0 : stmt->State = FETCHED;
100 0 : return SQL_NO_DATA;
101 : }
102 0 : if (stmt->startRow > 0 &&
103 0 : stmt->startRow + FetchOffset < 1 &&
104 0 : FetchOffset <= (SQLLEN) RowSetSize &&
105 0 : -FetchOffset <= (SQLLEN) RowSetSize) {
106 : /* Attempt to fetch before the result
107 : * set returned the first rowset */
108 0 : addStmtError(stmt, "01S06", NULL, 0);
109 0 : stmt->startRow = 0;
110 0 : break;
111 : }
112 0 : if (stmt->startRow + FetchOffset >= 0 &&
113 0 : stmt->startRow + FetchOffset < (SQLLEN) stmt->rowcount) {
114 0 : stmt->startRow += FetchOffset;
115 0 : break;
116 : }
117 0 : if (stmt->startRow + FetchOffset >= (SQLLEN) stmt->rowcount ||
118 0 : (stmt->startRow >= (SQLLEN) stmt->rowcount &&
119 : FetchOffset >= 0)) {
120 : /* after end */
121 0 : stmt->startRow = stmt->rowcount;
122 0 : stmt->rowSetSize = 0;
123 0 : stmt->State = FETCHED;
124 0 : return SQL_NO_DATA;
125 : }
126 : /* all bases should have been covered above */
127 0 : assert(0);
128 : }
129 : /* fall through */
130 : case SQL_FETCH_ABSOLUTE:
131 0 : if (FetchOffset < 0) {
132 0 : if ((unsigned int) -FetchOffset <= stmt->rowcount) {
133 0 : stmt->startRow = stmt->rowcount + FetchOffset;
134 0 : break;
135 : }
136 0 : stmt->startRow = 0;
137 0 : if ((unsigned int) -FetchOffset > RowSetSize) {
138 : /* before start */
139 0 : stmt->State = FETCHED;
140 0 : stmt->rowSetSize = 0;
141 0 : return SQL_NO_DATA;
142 : }
143 : /* Attempt to fetch before the result set
144 : returned the first rowset */
145 0 : addStmtError(stmt, "01S06", NULL, 0);
146 0 : break;
147 : }
148 0 : if (FetchOffset == 0) {
149 : /* before start */
150 0 : stmt->startRow = 0;
151 0 : stmt->rowSetSize = 0;
152 0 : stmt->State = FETCHED;
153 0 : return SQL_NO_DATA;
154 : }
155 0 : if ((SQLULEN) FetchOffset > stmt->rowcount) {
156 : /* after end */
157 0 : stmt->startRow = stmt->rowcount;
158 0 : stmt->rowSetSize = 0;
159 0 : stmt->State = FETCHED;
160 0 : return SQL_NO_DATA;
161 : }
162 0 : stmt->startRow = FetchOffset - 1;
163 0 : break;
164 0 : case SQL_FETCH_BOOKMARK:
165 : /* Optional feature not implemented */
166 0 : addStmtError(stmt, "HYC00", NULL, 0);
167 0 : return SQL_ERROR;
168 0 : default:
169 : /* Fetch type out of range */
170 0 : addStmtError(stmt, "HY106", NULL, 0);
171 0 : return SQL_ERROR;
172 : }
173 :
174 1001 : return MNDBFetch(stmt, RowStatusArray);
175 : }
176 :
177 : SQLRETURN SQL_API
178 : SQLFetchScroll(SQLHSTMT StatementHandle,
179 : SQLSMALLINT FetchOrientation,
180 : SQLLEN FetchOffset)
181 : {
182 1001 : ODBCStmt *stmt = (ODBCStmt *) StatementHandle;
183 :
184 : #ifdef ODBCDEBUG
185 1001 : ODBCLOG("SQLFetchScroll %p %s " LENFMT "\n",
186 : StatementHandle,
187 : translateFetchOrientation(FetchOrientation),
188 : LENCAST FetchOffset);
189 : #endif
190 :
191 1001 : if (!isValidStmt(stmt))
192 : return SQL_INVALID_HANDLE;
193 :
194 1001 : clearStmtErrors(stmt);
195 :
196 : /* check statement cursor state, query should be executed */
197 1001 : if (stmt->State < EXECUTED0 || stmt->State == EXTENDEDFETCHED) {
198 : /* Function sequence error */
199 0 : addStmtError(stmt, "HY010", NULL, 0);
200 0 : return SQL_ERROR;
201 : }
202 1001 : if (stmt->State == EXECUTED0) {
203 : /* Invalid cursor state */
204 0 : addStmtError(stmt, "24000", NULL, 0);
205 0 : return SQL_ERROR;
206 : }
207 :
208 1001 : return MNDBFetchScroll(stmt, FetchOrientation, FetchOffset,
209 1001 : stmt->ImplRowDescr->sql_desc_array_status_ptr);
210 : }
|