connected
+-- TEST using SQLExecute after SQLPrepare
+
Query: SELECT {fn CONCAT(?, ?) }
Param 1: foo
Param 2: bar
OUT param: 3
+Query: { ? = call concat(?::text, ?::text) }
+Param 1 is an OUT parameter
+Param 2: foo
+Param 3: bar
+Result set:
+
+OUT param: foobar
+
Query: SELECT {d '2014-12-21' } + '1 day'::interval
Result set:
2014-12-22 00:00:00
Query: SELECT {ts '2014-12-21 20:30:40' } + '1 day 1 hour 1 minute 1 second'::interval
Result set:
2014-12-22 21:31:41
+
+Query: {call a_b_c_d_e(?, ?::timestamp, ?, ?, ?)}
+Param 1 is an OUT parameter
+Param 2: 2017-02-23 11:34:46
+Param 3 is an I-O parameter
+Param 4: 3.4
+Param 5 is an OUT parameter
+Result set:
+6.7999999999999998 7 2017-02-24 11:34:46
+OUT params: 6.7999999999999998 : 7 : 2017-02-24 11:34:46
+
+-- TEST using SQLExecDirect
+
+Query: SELECT {fn CONCAT(?, ?) }
+Param 1: foo
+Param 2: bar
+Result set:
+foobar
+
+Query: SELECT {fn LOCATE(?, ?, 2) }
+Param 1: needle
+Param 2: this is a needle in an ol' haystack
+Result set:
+11
+
+Query: SELECT 'x' || {fn SPACE(10) } || 'x'
+Result set:
+x x
+
+Query: { call length(?) }
+Param 1: foobar
+Result set:
+6
+
+Query: { call right(?, ?) }
+Param 1: foobar
+Param 2: 3
+Result set:
+bar
+
+Query: { ? = call length('foo') }
+Param 1 is an OUT parameter
+Result set:
+
+OUT param: 3
+
+Query: { ? = call concat(?::text, ?::text) }
+Param 1 is an OUT parameter
+Param 2: foo
+Param 3: bar
+Result set:
+
+OUT param: foobar
+
+Query: SELECT {d '2014-12-21' } + '1 day'::interval
+Result set:
+2014-12-22 00:00:00
+
+Query: SELECT {t '20:30:40' } + '1 hour 1 minute 1 second'::interval
+Result set:
+21:31:41
+
+Query: SELECT {ts '2014-12-21 20:30:40' } + '1 day 1 hour 1 minute 1 second'::interval
+Result set:
+2014-12-22 21:31:41
+
+Query: {call a_b_c_d_e(?, ?::timestamp, ?, ?, ?)}
+Param 1 is an OUT parameter
+Param 2: 2017-02-23 11:34:46
+Param 3 is an I-O parameter
+Param 4: 3.4
+Param 5 is an OUT parameter
+Result set:
+6.7999999999999998 7 2017-02-24 11:34:46
+OUT params: 6.7999999999999998 : 7 : 2017-02-24 11:34:46
disconnecting
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "common.h"
}
static void
-bindOutParamString(HSTMT hstmt, int paramno, char *outbuf, int outbuflen)
+bindOutParamString(HSTMT hstmt, int paramno, char *outbuf, int outbuflen, BOOL inout)
{
SQLRETURN rc;
static SQLLEN cbParams[10];
- rc = SQLBindParameter(hstmt, paramno, SQL_PARAM_OUTPUT,
+ cbParams[paramno] = SQL_NTS;
+ rc = SQLBindParameter(hstmt, paramno, inout ? SQL_PARAM_INPUT_OUTPUT : SQL_PARAM_OUTPUT,
SQL_C_CHAR, /* value type */
SQL_CHAR, /* param type */
20, /* column size */
outbuflen, /* buffer len */
&cbParams[paramno] /* StrLen_or_IndPtr */);
CHECK_STMT_RESULT(rc, "SQLBindParameter failed", hstmt);
- printf("Param %d is an OUT parameter\n", paramno);
+ printf("Param %d is an %s parameter\n", paramno, inout ? "I-O": "OUT");
}
+static BOOL execDirectMode = FALSE;
+static SQLCHAR saveQuery[128];
+
static void
executeQuery(HSTMT hstmt)
{
SQLRETURN rc;
- rc = SQLExecute(hstmt);
+ if (execDirectMode)
+ rc = SQLExecDirect(hstmt, saveQuery, SQL_NTS);
+ else
+ rc = SQLExecute(hstmt);
CHECK_STMT_RESULT(rc, "SQLExecute failed", hstmt);
print_result(hstmt);
rc = SQLFreeStmt(hstmt, SQL_CLOSE);
{
SQLRETURN rc;
- rc = SQLPrepare(hstmt, (SQLCHAR *) str, SQL_NTS);
- CHECK_STMT_RESULT(rc, "SQLPrepare failed", hstmt);
+ if (execDirectMode)
+ strcpy(saveQuery, str);
+ else
+ {
+ rc = SQLPrepare(hstmt, (SQLCHAR *) str, SQL_NTS);
+ CHECK_STMT_RESULT(rc, "SQLPrepare failed", hstmt);
+ }
printf("\nQuery: %s\n", str);
}
-int main(int argc, char **argv)
+static void escape_test(HSTMT hstmt)
{
- SQLRETURN rc;
- HSTMT hstmt = SQL_NULL_HSTMT;
- char outbuf[10];
-
- 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);
- }
+ char outbuf1[64], outbuf3[64], outbuf5[64];
+ BOOL variadic_test_success = FALSE;
/**** Function escapes ****/
executeQuery(hstmt);
prepareQuery(hstmt, "{ ? = call length('foo') }");
- memset(outbuf, 0, sizeof(outbuf));
- bindOutParamString(hstmt, 1, outbuf, sizeof(outbuf) - 1);
+ memset(outbuf1, 0, sizeof(outbuf1));
+ bindOutParamString(hstmt, 1, outbuf1, sizeof(outbuf1) - 1, FALSE);
executeQuery(hstmt);
- printf("OUT param: %s\n", outbuf);
+ printf("OUT param: %s\n", outbuf1);
- /* TODO: This doesn't currently work.
- prepareQuery(hstmt, "{ ? = call concat(?, ?) }");
- memset(outbuf, 0, sizeof(outbuf));
- bindOutParamString(hstmt, 1, outbuf, sizeof(outbuf) - 1);
+ /* It's preferable to cast VARIADIC any fields */
+ prepareQuery(hstmt, "{ ? = call concat(?::text, ?::text) }");
+ memset(outbuf1, 0, sizeof(outbuf1));
+ bindOutParamString(hstmt, 1, outbuf1, sizeof(outbuf1) - 1, FALSE);
bindParamString(hstmt, 2, "foo");
bindParamString(hstmt, 3, "bar");
- executeQuery(hstmt);
- printf("OUT param: %s\n", outbuf);
- */
+ if (variadic_test_success)
+ executeQuery(hstmt);
+ else
+ printf("skip this test because it fails\n");
+ printf("OUT param: %s\n", outbuf1);
/**** Date, Time, and Timestamp literals ****/
prepareQuery(hstmt, "SELECT {ts '2014-12-21 20:30:40' } + '1 day 1 hour 1 minute 1 second'::interval");
executeQuery(hstmt);
+ /**** call procedure with out and i-o parameters ****/
+ prepareQuery(hstmt, "{call a_b_c_d_e(?, ?::timestamp, ?, ?, ?)}");
+ memset(outbuf1, 0, sizeof(outbuf1));
+ bindOutParamString(hstmt, 1, outbuf1, sizeof(outbuf1) - 1, FALSE);
+ bindParamString(hstmt, 2, "2017-02-23 11:34:46");
+ strcpy(outbuf3, "4");
+ bindOutParamString(hstmt, 3, outbuf3, sizeof(outbuf3) - 1, TRUE);
+ bindParamString(hstmt, 4, "3.4");
+ memset(outbuf5, 0, sizeof(outbuf5));
+ bindOutParamString(hstmt, 5, outbuf5, sizeof(outbuf5) - 1, FALSE);
+ executeQuery(hstmt);
+ printf("OUT params: %s : %s : %s\n", outbuf1, outbuf3, outbuf5);
+}
+
+int main(int argc, char **argv)
+{
+ SQLRETURN rc;
+ HSTMT hstmt = SQL_NULL_HSTMT;
+
+ 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);
+ }
+
+ rc = SQLExecDirect(hstmt, "create or replace function a_b_c_d_e"
+ "(out a float8, in b timestamp, inout c integer, "
+ "in d numeric, out e timestamp) returns record as "
+ "$function$ \n"
+ "DECLARE \n"
+ "BEGIN \n"
+ "a := 2 * d; \n"
+ "e := b + '1 day'::interval; \n"
+ "c := c + 3; \n"
+ "END; \n"
+ "$function$ \n"
+ "LANGUAGE plpgsql\n"
+ , SQL_NTS);
+ CHECK_STMT_RESULT(rc, "create function a_b_c_d_e failed", hstmt);
+
+ execDirectMode = FALSE;
+ printf("\n-- TEST using SQLExecute after SQLPrepare\n");
+ escape_test(hstmt);
+ execDirectMode = TRUE;
+ printf("\n-- TEST using SQLExecDirect\n");
+ escape_test(hstmt);
+
/* Clean up */
test_disconnect();