Skip to content

Commit 3b7ab43

Browse files
author
Michael Meskes
committed
Add Oracle like handling of char arrays.
In some cases Oracle Pro*C handles char array differently than ECPG. This patch adds a Oracle compatibility mode to make ECPG behave like Pro*C. Patch by David Rader <davidr@openscg.com>
1 parent db2fc80 commit 3b7ab43

File tree

12 files changed

+513
-5
lines changed

12 files changed

+513
-5
lines changed

src/interfaces/ecpg/ecpglib/data.c

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,45 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
464464

465465
if (varcharsize == 0 || varcharsize > size)
466466
{
467-
strncpy(str, pval, size + 1);
467+
/* compatibility mode, blank pad and null terminate char array */
468+
if (ORACLE_MODE(compat) && (type == ECPGt_char || type == ECPGt_unsigned_char))
469+
{
470+
memset(str, ' ', varcharsize);
471+
memcpy(str, pval, size);
472+
str[varcharsize-1] = '\0';
473+
474+
/* compatiblity mode empty string gets -1 indicator but no warning */
475+
if (size == 0) {
476+
/* truncation */
477+
switch (ind_type)
478+
{
479+
case ECPGt_short:
480+
case ECPGt_unsigned_short:
481+
*((short *) (ind + ind_offset * act_tuple)) = -1;
482+
break;
483+
case ECPGt_int:
484+
case ECPGt_unsigned_int:
485+
*((int *) (ind + ind_offset * act_tuple)) = -1;
486+
break;
487+
case ECPGt_long:
488+
case ECPGt_unsigned_long:
489+
*((long *) (ind + ind_offset * act_tuple)) = -1;
490+
break;
491+
#ifdef HAVE_LONG_LONG_INT
492+
case ECPGt_long_long:
493+
case ECPGt_unsigned_long_long:
494+
*((long long int *) (ind + ind_offset * act_tuple)) = -1;
495+
break;
496+
#endif /* HAVE_LONG_LONG_INT */
497+
default:
498+
break;
499+
}
500+
}
501+
}
502+
else
503+
{
504+
strncpy(str, pval, size + 1);
505+
}
468506
/* do the rtrim() */
469507
if (type == ECPGt_string)
470508
{
@@ -481,7 +519,14 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
481519
{
482520
strncpy(str, pval, varcharsize);
483521

484-
if (varcharsize < size)
522+
/* compatibility mode, null terminate char array */
523+
if (ORACLE_MODE(compat) && (varcharsize - 1) < size)
524+
{
525+
if (type == ECPGt_char || type == ECPGt_unsigned_char)
526+
str[varcharsize-1] = '\0';
527+
}
528+
529+
if (varcharsize < size || (ORACLE_MODE(compat) && (varcharsize - 1) < size))
485530
{
486531
/* truncation */
487532
switch (ind_type)

src/interfaces/ecpg/ecpglib/extern.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515

1616
enum COMPAT_MODE
1717
{
18-
ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE
18+
ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE, ECPG_COMPAT_ORACLE
1919
};
2020

2121
extern bool ecpg_internal_regression_mode;
2222

2323
#define INFORMIX_MODE(X) ((X) == ECPG_COMPAT_INFORMIX || (X) == ECPG_COMPAT_INFORMIX_SE)
24+
#define ORACLE_MODE(X) ((X) == ECPG_COMPAT_ORACLE)
2425

2526
enum ARRAY_TYPE
2627
{

src/interfaces/ecpg/preproc/ecpg.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ help(const char *progname)
4141
printf(_(" -c automatically generate C code from embedded SQL code;\n"
4242
" this affects EXEC SQL TYPE\n"));
4343
printf(_(" -C MODE set compatibility mode; MODE can be one of\n"
44-
" \"INFORMIX\", \"INFORMIX_SE\"\n"));
44+
" \"INFORMIX\", \"INFORMIX_SE\", \"ORACLE\"\n"));
4545
#ifdef YYDEBUG
4646
printf(_(" -d generate parser debug output\n"));
4747
#endif
@@ -208,6 +208,10 @@ main(int argc, char *const argv[])
208208
snprintf(informix_path, MAXPGPATH, "%s/informix/esql", pkginclude_path);
209209
add_include_path(informix_path);
210210
}
211+
else if (strncmp(optarg, "ORACLE", strlen("ORACLE")) == 0)
212+
{
213+
compat = ECPG_COMPAT_ORACLE;
214+
}
211215
else
212216
{
213217
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);

src/interfaces/ecpg/preproc/extern.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,12 @@ extern int filtered_base_yylex(void);
122122

123123
enum COMPAT_MODE
124124
{
125-
ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE
125+
ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX, ECPG_COMPAT_INFORMIX_SE, ECPG_COMPAT_ORACLE
126126
};
127127
extern enum COMPAT_MODE compat;
128128

129129
#define INFORMIX_MODE (compat == ECPG_COMPAT_INFORMIX || compat == ECPG_COMPAT_INFORMIX_SE)
130+
#define ORACLE_MODE (compat == ECPG_COMPAT_ORACLE)
131+
130132

131133
#endif /* _ECPG_PREPROC_EXTERN_H */

src/interfaces/ecpg/test/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ all install installdirs uninstall distprep:
3030
$(MAKE) -C pgtypeslib $@
3131
$(MAKE) -C preproc $@
3232
$(MAKE) -C compat_informix $@
33+
$(MAKE) -C compat_oracle $@
3334
$(MAKE) -C thread $@
3435

3536
clean distclean maintainer-clean:
@@ -38,6 +39,7 @@ clean distclean maintainer-clean:
3839
$(MAKE) -C pgtypeslib $@
3940
$(MAKE) -C preproc $@
4041
$(MAKE) -C compat_informix $@
42+
$(MAKE) -C compat_oracle $@
4143
$(MAKE) -C thread $@
4244
rm -rf tmp_check results log
4345
rm -f pg_regress regression.diffs regression.out pg_regress_ecpg.o $(WIN32RES)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/char_array
2+
/char_array.c
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
subdir = src/interfaces/ecpg/test/compat_oracle
2+
top_builddir = ../../../../..
3+
include $(top_builddir)/src/Makefile.global
4+
include $(top_srcdir)/$(subdir)/../Makefile.regress
5+
6+
# Use special oracle compatibility switch for all tests in this directory
7+
ECPG += -C ORACLE
8+
9+
TESTS = char_array char_array.c
10+
11+
all: $(TESTS)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
EXEC SQL INCLUDE ../regression;
6+
7+
static void warn();
8+
9+
/* Compatible handling of char array to retrieve varchar field to char array
10+
should be fixed-length, blank-padded, then null-terminated.
11+
Conforms to the ANSI Fixed Character type. */
12+
13+
int main() {
14+
15+
ECPGdebug(1, stderr);
16+
EXEC SQL CONNECT TO REGRESSDB1;
17+
18+
EXEC SQL WHENEVER SQLWARNING do warn();
19+
EXEC SQL WHENEVER SQLERROR SQLPRINT;
20+
21+
const char *ppppp = "XXXXX";
22+
23+
EXEC SQL BEGIN DECLARE SECTION;
24+
char shortstr[5];
25+
char bigstr[11];
26+
short shstr_ind = 0;
27+
short bigstr_ind = 0;
28+
EXEC SQL END DECLARE SECTION;
29+
30+
EXEC SQL CREATE TABLE strdbase (strval varchar(10));
31+
EXEC SQL INSERT INTO strdbase values ('');
32+
EXEC SQL INSERT INTO strdbase values ('AB');
33+
EXEC SQL INSERT INTO strdbase values ('ABCD');
34+
EXEC SQL INSERT INTO strdbase values ('ABCDE');
35+
EXEC SQL INSERT INTO strdbase values ('ABCDEF');
36+
EXEC SQL INSERT INTO strdbase values ('ABCDEFGHIJ');
37+
38+
EXEC SQL declare C cursor for select strval, strval from strdbase;
39+
EXEC SQL OPEN C;
40+
41+
EXEC SQL WHENEVER NOT FOUND DO BREAK;
42+
43+
printf("Full Str. : Short Ind.\n");
44+
while(1) {
45+
strncpy(shortstr, ppppp, sizeof shortstr);
46+
memset(bigstr, 0, sizeof bigstr);
47+
EXEC SQL FETCH C into :bigstr :bigstr_ind, :shortstr :shstr_ind;
48+
printf("\"%s\": \"%s\" %d\n", bigstr, shortstr, shstr_ind);
49+
}
50+
51+
EXEC SQL close cstr;
52+
EXEC SQL DROP TABLE strdbase;
53+
54+
printf("\nGOOD-BYE!!\n\n");
55+
56+
EXEC SQL COMMIT WORK;
57+
58+
EXEC SQL DISCONNECT ALL;
59+
60+
return 0;
61+
}
62+
63+
static void warn(void)
64+
{
65+
fprintf(stderr, "Warning: At least one column was truncated\n");
66+
}

src/interfaces/ecpg/test/ecpg_schedule

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ test: compat_informix/sqlda
77
test: compat_informix/describe
88
test: compat_informix/test_informix
99
test: compat_informix/test_informix2
10+
test: compat_oracle/char_array
1011
test: connect/test2
1112
test: connect/test3
1213
test: connect/test4

0 commit comments

Comments
 (0)