summaryrefslogtreecommitdiff
path: root/test/src/cursors-test.c
blob: b6dcf62fab1ec59df4a2d11feefd296975650a99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "common.h"

static void
testLargeResult(HSTMT hstmt, int betweenstmts)
{
	int rc;
	int i;

	rc = SQLSetConnectAttr(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF, 0);
	CHECK_CONN_RESULT(rc, "SQL_AUTOCOMMIT off failed", conn);
	/*
	 * Fetch a large result set without cursor (in Declare/fetch mode, it will
	 * be fetched in chunks)
	 */
	rc = SQLExecDirect(hstmt, (SQLCHAR *) "SELECT 'foo' || g FROM generate_series(1, 3210) g", SQL_NTS);
	CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt);

	/* Fetch the first 10 rows */
	for (i = 0; i < 10; i++)
	{
		char buf[40];
		SQLLEN ind;

		rc = SQLFetch(hstmt);
		if (rc != SQL_SUCCESS)
		{
			CHECK_STMT_RESULT(rc, "SQLFetch failed", hstmt);
		}

		rc = SQLGetData(hstmt, 1, SQL_C_CHAR, buf, sizeof(buf), &ind);
		CHECK_STMT_RESULT(rc, "SQLGetData failed", hstmt);
		printf("%s ", buf);
	}

	/* Now Commit, Rollback or do nothing depending on the argument */
	switch (betweenstmts)
	{
		case 1:
			printf("\nCommit\n");
			rc = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT);
			CHECK_STMT_RESULT(rc, "SQLEndTran failed\n", hstmt);
			break;

		case 2:
			printf("\nRollback\n");
			rc = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_ROLLBACK);
			CHECK_STMT_RESULT(rc, "SQLEndTran failed\n", hstmt);
			break;
		default:
			/* do nothing */
			break;
	}

	/*
	 * Try to fetch the rest of the result set.
	 * (Will fail in SQL_CB_CLOSE mode and succeed in SQL_CB_PRESERVE).
	 */
	for (;; i++)
	{
		char buf[40];
		SQLLEN ind;

		rc = SQLFetch(hstmt);
		if (rc == SQL_NO_DATA)
			break;
		if (rc != SQL_SUCCESS)
		{
			char sqlstate[32] = "";
			SQLINTEGER nativeerror;
			SQLSMALLINT textlen;

			SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sqlstate, &nativeerror,
						  NULL, 0, &textlen);
			if (strcmp(sqlstate, "HY010") == 0)
			{
				/* This is expected in SQL_CB_CLOSE mode */
				printf("SQLFetch failed with HY010 (which probably means that the cursor was closed at commit/rollback)");
				break;
			}
			else
				CHECK_STMT_RESULT(rc, "SQLGetDiagRec failed", hstmt);
		}

		rc = SQLGetData(hstmt, 1, SQL_C_CHAR, buf, sizeof(buf), &ind);
		CHECK_STMT_RESULT(rc, "SQLGetData failed", hstmt);
		if (i == 20)
			printf("... ");
		else if (20 < i && i <= 3205)
		{
			/* skip printing, to keep the output short */
		}
		else
			printf("%s ", buf);
	}
	printf("\nFetched %d rows altogether\n\n", i);

	rc = SQLFreeStmt(hstmt, SQL_CLOSE);
	CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
}

static const char *
sql_commit_behavior_str(SQLUINTEGER info)
{
	static char buf[50];

	switch(info)
	{
		case SQL_CB_DELETE:
			return "SQL_CB_DELETE";

		case SQL_CB_CLOSE:
			return "SQL_CB_CLOSE";

		case SQL_CB_PRESERVE:
			return "SQL_CB_PRESERVE";

		default:
			sprintf(buf, "unknown (%u)", (unsigned int) info);
			return buf;
	}
}

int main(int argc, char **argv)
{
	int rc;
	HSTMT hstmt = SQL_NULL_HSTMT;
	SQLUSMALLINT info;

	test_connect();

	rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
	if (!SQL_SUCCEEDED(rc))
	{
		print_diag("failed to allocate stmt handle", SQL_HANDLE_DBC, conn);
		exit(1);
	}

	/*
	 * Print out the current SQL_CURSOR_COMMIT_BEHAVIOR and
	 * SQL_CURSOR_ROLLBACK settings. The result of this test case depends on
	 * those.
	 */
	rc = SQLGetInfo(conn, SQL_CURSOR_COMMIT_BEHAVIOR, &info, sizeof(info), NULL);
	CHECK_STMT_RESULT(rc, "SQLGetInfo failed", hstmt);
	printf("SQL_CURSOR_COMMIT_BEHAVIOR: %s\n", sql_commit_behavior_str(info));

	rc = SQLGetInfo(conn, SQL_CURSOR_ROLLBACK_BEHAVIOR, &info, sizeof(info), NULL);
	CHECK_STMT_RESULT(rc, "SQLGetInfo failed", hstmt);
	printf("SQL_CURSOR_ROLLBACK_BEHAVIOR: %s\n\n", sql_commit_behavior_str(info));

	/* Run three variations of the test */
	testLargeResult(hstmt, 0);
	testLargeResult(hstmt, 1);
	testLargeResult(hstmt, 2);

	/* Clean up */
	test_disconnect();

	return 0;
}