tdbc::postgres

Check-in [16ac5a167d]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to tclconference@googlegroups.com
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:TEA update. Make pqStubs a const table. Adapt postgres library name to real library name on Cygwin (cygpq-5.dll).
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:16ac5a167d2753e34b430fdfeff32a0d48b4fc43
User & Date: jan.nijtmans 2015-06-26 13:48:48
Context
2015-10-05
12:06
re-generate "configure" with latest TEA. configure win/*.vc files to crlf line-endings. check-in: 97ecc76cd9 user: jan.nijtmans tags: trunk
2015-06-26
13:48
TEA update. Make pqStubs a const table. Adapt postgres library name to real library name on Cygwin (cygpq-5.dll). check-in: 16ac5a167d user: jan.nijtmans tags: trunk
2015-05-08
14:20
TEA update check-in: fff3a98d84 user: dgp tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
..
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
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
...
167
168
169
170
171
172
173



174
175
176
177
178
179
180
...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# Copyright (c) 2002-2005 ActiveState Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: Makefile.in,v 1.64 2007/10/23 22:08:06 hobbs Exp $

#========================================================================
# Add additional lines to handle any additional AC_SUBST cases that
# have been added in a customized configure script.
#========================================================================

#SAMPLE_NEW_VAR	= @SAMPLE_NEW_VAR@

#========================================================================
# Nothing of the variables below this line should need to be changed.
# Please check the TARGETS section below to make sure the make targets
# are correct.
#========================================================================

#========================================================================
................................................................................
CFLAGS_WARNING	= @CFLAGS_WARNING@
EXEEXT		= @EXEEXT@
LDFLAGS_DEFAULT	= @LDFLAGS_DEFAULT@
MAKE_LIB	= @MAKE_LIB@
MAKE_SHARED_LIB	= @MAKE_SHARED_LIB@
MAKE_STATIC_LIB	= @MAKE_STATIC_LIB@
MAKE_STUB_LIB	= @MAKE_STUB_LIB@
ADD_MANIFEST    = @ADD_MANIFEST@
OBJEXT		= @OBJEXT@
RANLIB		= @RANLIB@
RANLIB_STUB	= @RANLIB_STUB@
SHLIB_CFLAGS	= @SHLIB_CFLAGS@
SHLIB_LD	= @SHLIB_LD@
SHLIB_LD_LIBS	= @SHLIB_LD_LIBS@
STLIB_LD	= @STLIB_LD@
................................................................................
# to test against an uninstalled Tcl.  Add special env vars that you
# require for testing here (like TCLX_LIBRARY).
#========================================================================

EXTRA_PATH	= $(top_builddir):$(TCL_BIN_DIR)
#EXTRA_PATH	= $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR)
TCLLIBPATH	= $(top_builddir)
TCLSH_ENV	= TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library`

PKG_ENV		= @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \
		  PATH="$(EXTRA_PATH):$(PATH)" \
		  TCLLIBPATH="$(TCLLIBPATH)" \
		  TDBCPOSTGRES_LIBRARY=`@CYGPATH@ $(srcdir)/library`

TCLSH_PROG	= @TCLSH_PROG@
TCLSH   	= $(PKG_ENV) $(TCLSH_ENV) $(TCLSH_PROG)
................................................................................

#WISH_ENV	= TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library`
#WISH_PROG	= @WISH_PROG@
#WISH   	= $(PKG_ENV) $(TCLSH_ENV) $(WISH_ENV) $(WISH_PROG)

SHARED_BUILD	= @SHARED_BUILD@

INCLUDES	= @PKG_INCLUDES@ @TCL_INCLUDES@ 
# INCLUDES	= @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@

PKG_CFLAGS	= @PKG_CFLAGS@

# TCL_DEFS is not strictly need here, but if you remove it, then you
# must make sure that configure.in checks for the necessary components
# that your library may use.  TCL_DEFS can actually be a problem if
# you do not compile with a similar machine setup as the Tcl core was
# compiled with.
#DEFS		= $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS)
DEFS		= @DEFS@ $(PKG_CFLAGS)

# Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile
................................................................................

CPPFLAGS	= @CPPFLAGS@
LIBS		= @PKG_LIBS@ @LIBS@
AR		= @AR@
CFLAGS		= @CFLAGS@
COMPILE		= $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)




#========================================================================
# Start of user-definable TARGETS section
#========================================================================

#========================================================================
# TEA TARGETS.  Please note that the "libraries:" target refers to platform
# independent files, and the "binaries:" target inclues executable programs and
................................................................................
# library.  In most cases these object files will correspond to the
# source files above.
#========================================================================

$(PKG_LIB_FILE): $(PKG_OBJECTS)
	-rm -f $(PKG_LIB_FILE)
	${MAKE_LIB}
	$(ADD_MANIFEST)
	$(RANLIB) $(PKG_LIB_FILE)

#========================================================================
# We need to enumerate the list of .c to .o lines here.
#
# In the following lines, $(srcdir) refers to the toplevel directory
# containing your extension.  If your sources are in a subdirectory,
................................................................................
dist-clean:
	rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.*

dist: dist-clean
	mkdir -p $(DIST_DIR)
	cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \
		$(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \
		$(DIST_DIR)/
	chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4
	chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in

	for i in $(srcdir)/*.[ch]; do \
	    if [ -f $$i ]; then \
		cp -p $$i $(DIST_DIR)/ ; \
	    fi; \
	done;

................................................................................

#========================================================================
# End of user-definable section
#========================================================================

#========================================================================
# Don't modify the file to clean here.  Instead, set the "CLEANFILES"
# variable in configure.in
#========================================================================

clean:  
	-test -z "$(BINARIES)" || rm -f $(BINARIES)
	-rm -f *.$(OBJEXT) core *.core
	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)

distclean: clean
	-rm -f *.tab.c
	-rm -f $(CONFIGURE_OUTPUTS)







<
<
<
<
<
<
<







 







<







 







|
>







 







|





|







 







>
>
>







 







<







 







|

|







 







|


|







10
11
12
13
14
15
16







17
18
19
20
21
22
23
..
91
92
93
94
95
96
97

98
99
100
101
102
103
104
...
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
...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
...
256
257
258
259
260
261
262

263
264
265
266
267
268
269
...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
...
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# Copyright (c) 2002-2005 ActiveState Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: Makefile.in,v 1.64 2007/10/23 22:08:06 hobbs Exp $








#========================================================================
# Nothing of the variables below this line should need to be changed.
# Please check the TARGETS section below to make sure the make targets
# are correct.
#========================================================================

#========================================================================
................................................................................
CFLAGS_WARNING	= @CFLAGS_WARNING@
EXEEXT		= @EXEEXT@
LDFLAGS_DEFAULT	= @LDFLAGS_DEFAULT@
MAKE_LIB	= @MAKE_LIB@
MAKE_SHARED_LIB	= @MAKE_SHARED_LIB@
MAKE_STATIC_LIB	= @MAKE_STATIC_LIB@
MAKE_STUB_LIB	= @MAKE_STUB_LIB@

OBJEXT		= @OBJEXT@
RANLIB		= @RANLIB@
RANLIB_STUB	= @RANLIB_STUB@
SHLIB_CFLAGS	= @SHLIB_CFLAGS@
SHLIB_LD	= @SHLIB_LD@
SHLIB_LD_LIBS	= @SHLIB_LD_LIBS@
STLIB_LD	= @STLIB_LD@
................................................................................
# to test against an uninstalled Tcl.  Add special env vars that you
# require for testing here (like TCLX_LIBRARY).
#========================================================================

EXTRA_PATH	= $(top_builddir):$(TCL_BIN_DIR)
#EXTRA_PATH	= $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR)
TCLLIBPATH	= $(top_builddir)
TCLSH_ENV	= TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \
		  TDBC_LIBRARY=`@CYGPATH@ @tdbc_LIBRARY_PATH@`
PKG_ENV		= @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \
		  PATH="$(EXTRA_PATH):$(PATH)" \
		  TCLLIBPATH="$(TCLLIBPATH)" \
		  TDBCPOSTGRES_LIBRARY=`@CYGPATH@ $(srcdir)/library`

TCLSH_PROG	= @TCLSH_PROG@
TCLSH   	= $(PKG_ENV) $(TCLSH_ENV) $(TCLSH_PROG)
................................................................................

#WISH_ENV	= TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library`
#WISH_PROG	= @WISH_PROG@
#WISH   	= $(PKG_ENV) $(TCLSH_ENV) $(WISH_ENV) $(WISH_PROG)

SHARED_BUILD	= @SHARED_BUILD@

INCLUDES	= @PKG_INCLUDES@ @TCL_INCLUDES@
# INCLUDES	= @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@

PKG_CFLAGS	= @PKG_CFLAGS@

# TCL_DEFS is not strictly need here, but if you remove it, then you
# must make sure that configure.ac checks for the necessary components
# that your library may use.  TCL_DEFS can actually be a problem if
# you do not compile with a similar machine setup as the Tcl core was
# compiled with.
#DEFS		= $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS)
DEFS		= @DEFS@ $(PKG_CFLAGS)

# Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile
................................................................................

CPPFLAGS	= @CPPFLAGS@
LIBS		= @PKG_LIBS@ @LIBS@
AR		= @AR@
CFLAGS		= @CFLAGS@
COMPILE		= $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)

VALGRIND		= valgrind
VALGRINDARGS		= --tool=memcheck --num-callers=16 --leak-resolution=high --leak-check=yes --show-reachable=yes -v

#========================================================================
# Start of user-definable TARGETS section
#========================================================================

#========================================================================
# TEA TARGETS.  Please note that the "libraries:" target refers to platform
# independent files, and the "binaries:" target inclues executable programs and
................................................................................
# library.  In most cases these object files will correspond to the
# source files above.
#========================================================================

$(PKG_LIB_FILE): $(PKG_OBJECTS)
	-rm -f $(PKG_LIB_FILE)
	${MAKE_LIB}

	$(RANLIB) $(PKG_LIB_FILE)

#========================================================================
# We need to enumerate the list of .c to .o lines here.
#
# In the following lines, $(srcdir) refers to the toplevel directory
# containing your extension.  If your sources are in a subdirectory,
................................................................................
dist-clean:
	rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.*

dist: dist-clean
	mkdir -p $(DIST_DIR)
	cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \
		$(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \
		$(srcdir)/configure.ac $(DIST_DIR)/
	chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4
	chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.ac

	for i in $(srcdir)/*.[ch]; do \
	    if [ -f $$i ]; then \
		cp -p $$i $(DIST_DIR)/ ; \
	    fi; \
	done;

................................................................................

#========================================================================
# End of user-definable section
#========================================================================

#========================================================================
# Don't modify the file to clean here.  Instead, set the "CLEANFILES"
# variable in configure.ac
#========================================================================

clean:
	-test -z "$(BINARIES)" || rm -f $(BINARIES)
	-rm -f *.$(OBJEXT) core *.core
	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)

distclean: clean
	-rm -f *.tab.c
	-rm -f $(CONFIGURE_OUTPUTS)

Changes to aclocal.m4.

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
    TEAX_FOREACH(i, $@, [
	# check for existence, be strict because it should be present!
	AS_IF([test ! -f "${srcdir}/$i"], [
	    AC_MSG_ERROR([could not find header file '${srcdir}/$i'])])
	TEAX_LAPPEND(PKG_PRIVATE_HEADERS, $i)])
    AC_SUBST(PKG_PRIVATE_HEADERS)])

dnl Extra magic to make things work with Vista and VC
AC_DEFUN([TEAX_VC_MANIFEST], [
    ADD_MANIFEST=":"
    AS_IF([test "$GCC" != yes \
	    -a ${TEA_PLATFORM} == "windows" \
	    -a "${SHARED_BUILD}" = "1"], [
	# This refers to "Manifest Tool" not "Magnetic Tape utility"
	AC_CHECK_PROGS(MT, mt, none)
	AS_IF([test "$MT" != none], [
	    ADD_MANIFEST="${MT} -nologo -manifest [\$]@.manifest -outputresource:[\$]@\;2"
	    CLEANFILES="$CLEANFILES ${PKG_LIB_FILE}.manifest"])])
    AC_SUBST(ADD_MANIFEST)])

AC_DEFUN([TEAX_SDX], [
    AC_PATH_PROG(SDX, sdx, none)
    TEAX_IFEQ($SDX, none, [
	AC_PATH_PROG(SDX_KIT, sdx.kit, none)
	TEAX_IFNEQ($SDX_KIT, none, [
	    # We assume that sdx.kit is on the path, and that the default
	    # tclsh is activetcl







<
<
<
<
<
<
<
<
<
<
<
<
<







50
51
52
53
54
55
56













57
58
59
60
61
62
63
    TEAX_FOREACH(i, $@, [
	# check for existence, be strict because it should be present!
	AS_IF([test ! -f "${srcdir}/$i"], [
	    AC_MSG_ERROR([could not find header file '${srcdir}/$i'])])
	TEAX_LAPPEND(PKG_PRIVATE_HEADERS, $i)])
    AC_SUBST(PKG_PRIVATE_HEADERS)])














AC_DEFUN([TEAX_SDX], [
    AC_PATH_PROG(SDX, sdx, none)
    TEAX_IFEQ($SDX, none, [
	AC_PATH_PROG(SDX_KIT, sdx.kit, none)
	TEAX_IFNEQ($SDX_KIT, none, [
	    # We assume that sdx.kit is on the path, and that the default
	    # tclsh is activetcl

Changes to configure.

618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
....
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
....
2574
2575
2576
2577
2578
2579
2580






























2581
2582
2583
2584
2585
2586
2587
....
3636
3637
3638
3639
3640
3641
3642







3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
....
5995
5996
5997
5998
5999
6000
6001







6002
6003
6004
6005
6006
6007
6008
....
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
....
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083



6084

6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
....
9108
9109
9110
9111
9112
9113
9114
9115
9116
9117
9118
9119
9120
9121
9122
9123
9124
....
9438
9439
9440
9441
9442
9443
9444
9445
9446
9447
9448
9449
9450
9451
9452
9453
9454
9455
9456
9457
9458
9459
9460
9461
9462
9463
9464
9465
9466
9467
9468
9469
9470
9471
9472
9473
9474
9475
9476
9477
9478
9479
9480
9481
9482
9483
9484
9485
9486
9487
9488
9489
9490
9491
9492
9493
9494
9495
9496
9497
9498
9499
9500
9501
9502
9503
9504
9505
9506
9507
9508
....
9543
9544
9545
9546
9547
9548
9549
9550
9551
9552
9553
9554
9555
9556
9557
.....
10706
10707
10708
10709
10710
10711
10712
10713
10714
10715
# include <unistd.h>
#endif"

ac_subst_vars='LTLIBOBJS
LIBOBJS
CONFIGURE_OUTPUTS
TCLSH_PROG
ADD_MANIFEST
MT
VC_MANIFEST_EMBED_EXE
VC_MANIFEST_EMBED_DLL
RANLIB_STUB
MAKE_STUB_LIB
MAKE_STATIC_LIB
MAKE_SHARED_LIB
MAKE_LIB
................................................................................


#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------

ac_aux_dir=
for ac_dir in tclconfig "$srcdir"/tclconfig; do
  if test -f "$ac_dir/install-sh"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install-sh -c"
    break
  elif test -f "$ac_dir/install.sh"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install.sh -c"
    break
  elif test -f "$ac_dir/shtool"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/shtool install -c"
    break
  fi
done
if test -z "$ac_aux_dir"; then
  as_fn_error $? "cannot find install-sh, install.sh, or shtool in tclconfig \"$srcdir\"/tclconfig" "$LINENO" 5
fi

# These three variables are undocumented and unsupported,
# and are intended to be withdrawn in a future Autoconf release.
# They can cause serious problems if a builder's source tree is in a directory
# whose full name contains unusual characters.
ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.



    # TEA extensions pass this us the version of TEA they think they
    # are compatible with.
    TEA_VERSION="3.9"

    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5
................................................................................







































#--------------------------------------------------------------------
# Load the tclConfig.sh file
#--------------------------------------------------------------------


................................................................................















#--------------------------------------------------------------------
# Load the tclooConfig.sh file on Tcl versions where oo is an
# extension.
#--------------------------------------------------------------------

if test "${TCL_MAJOR_VERSION}" -lt 8 ; then
    as_fn_error $? "${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6 or newer.
Found configuration for Tcl ${TCL_VERSION}." "$LINENO" 5
fi
if test "${TCL_MAJOR_VERSION}" -eq 8 ; then
  if test "${TCL_MINOR_VERSION}" -lt 6 ; then
    as_fn_error $? "${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6 or newer.
Found configuration for Tcl ${TCL_VERSION}." "$LINENO" 5
  fi
  TCLOO_CFLAGS=''
fi
TCL_VERSION_REQ=8.6;


    #
    # Ok, lets find the tdbc configuration
    # First, look for one uninstalled.
................................................................................


  fi
fi

    PKG_CFLAGS="$PKG_CFLAGS ${TCLOO_CFLAGS}"









if test "x${TEA_PLATFORM}" = "xwindows" -a "x${GCC}" != "xyes" ; then

    vars="\"`${CYGPATH} ${tdbc_STUB_LIB_PATH}`\""
    for i in $vars; do
	if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
	    # Convert foo.lib to -lfoo for GCC.  No-op if not *.lib
................................................................................
	    i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'`
	fi
	PKG_LIBS="$PKG_LIBS $i"
    done


fi

    vars="${tdbc_INCLUDE_SPEC}"
    for i in $vars; do
	PKG_INCLUDES="$PKG_INCLUDES $i"
    done



    PKG_CFLAGS="$PKG_CFLAGS ${tdbc_CFLAGS}"



    vars=""
    for i in $vars; do
................................................................................
	fi
	PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i"
    done



#--------------------------------------------------------------------
# A few miscellaneous platform-specific items:
#
# Define a special symbol for Windows (BUILD_sample in this case) so
# that we create the export library with the dll.
#
# Windows creates a few extra files that need to be cleaned up.
# You can add more files to clean if your extension creates any extra
# files.



#

# TEA_ADD_* any platform specific compiler/build info here.
#--------------------------------------------------------------------

# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
#CLEANFILES="$CLEANFILES pkgIndex.tcl"

if test "${TEA_PLATFORM}" = "windows" ; then
    $as_echo "#define _WIN32 1" >>confdefs.h

fi

#--------------------------------------------------------------------
# Choose which headers you need.  Extension authors should try very
# hard to only rely on the Tcl public header files.  Internal headers
# contain private data structures and are subject to change without
# notice.
# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG
#--------------------------------------------------------------------
................................................................................
# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
# link against the non-stubbed Tcl library.  Add Tk too if necessary.
#--------------------------------------------------------------------


$as_echo "#define USE_TCL_STUBS 1" >>confdefs.h


$as_echo "#define USE_TK_STUBS 1" >>confdefs.h


#--------------------------------------------------------------------
# We need the INT2PTR and PTR2INT macros, so make sure that intptr_t
# is defined.
#--------------------------------------------------------------------

for ac_header in stdint.h sys/types.h
................................................................................








    ADD_MANIFEST=":"
    if test "$GCC" != yes \
	    -a ${TEA_PLATFORM} == "windows" \
	    -a "${SHARED_BUILD}" = "1"; then :

	# This refers to "Manifest Tool" not "Magnetic Tape utility"
	for ac_prog in mt
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_MT+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$MT"; then
  ac_cv_prog_MT="$MT" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
    ac_cv_prog_MT="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
MT=$ac_cv_prog_MT
if test -n "$MT"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MT" >&5
$as_echo "$MT" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$MT" && break
done
test -n "$MT" || MT="none"

	if test "$MT" != none; then :

	    ADD_MANIFEST="${MT} -nologo -manifest \$@.manifest -outputresource:\$@\;2"
	    CLEANFILES="$CLEANFILES ${PKG_LIB_FILE}.manifest"
fi
fi


#--------------------------------------------------------------------
# Determine the name of the tclsh and/or wish executables in the
# Tcl and Tk build directories or the location they were installed
# into. These paths are used to support running test cases only,
# the Makefile should not be making use of these paths to generate
# a pkgIndex.tcl file or anything else at extension build time.
................................................................................

#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
# You may alternatively have a special pkgIndex.tcl.in or other files
# which require substituting th AC variables in.  Include these here.
#--------------------------------------------------------------------

CONFIGURE_OUTPUTS="Makefile pkgIndex.tcl tdbcConfig.sh config.cache config.log config.status"


ac_config_files="$ac_config_files Makefile pkgIndex.tcl"

cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
................................................................................
  $ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi


# This is a comment added to force the 'execute' permission to update
# in the Fossil repository.







<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>











|
|

|
|







 







>
>
>
>
>
>
>







 







<
<
<
<
<
<
<







 







<

<
<
<
<

<
>
>
>

>



<
<


<
<
<
<
<







 







<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|







 







<
<
<
618
619
620
621
622
623
624


625
626
627
628
629
630
631
....
2421
2422
2423
2424
2425
2426
2427





























2428
2429
2430
2431
2432
2433
2434
....
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
....
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
....
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
....
6034
6035
6036
6037
6038
6039
6040







6041
6042
6043
6044
6045
6046
6047
....
6075
6076
6077
6078
6079
6080
6081

6082




6083

6084
6085
6086
6087
6088
6089
6090
6091


6092
6093





6094
6095
6096
6097
6098
6099
6100
....
9105
9106
9107
9108
9109
9110
9111



9112
9113
9114
9115
9116
9117
9118
....
9432
9433
9434
9435
9436
9437
9438

























































9439
9440
9441
9442
9443
9444
9445
....
9480
9481
9482
9483
9484
9485
9486
9487
9488
9489
9490
9491
9492
9493
9494
.....
10643
10644
10645
10646
10647
10648
10649



# include <unistd.h>
#endif"

ac_subst_vars='LTLIBOBJS
LIBOBJS
CONFIGURE_OUTPUTS
TCLSH_PROG


VC_MANIFEST_EMBED_EXE
VC_MANIFEST_EMBED_DLL
RANLIB_STUB
MAKE_STUB_LIB
MAKE_STATIC_LIB
MAKE_SHARED_LIB
MAKE_LIB
................................................................................


#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------































    # TEA extensions pass this us the version of TEA they think they
    # are compatible with.
    TEA_VERSION="3.9"

    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5
................................................................................









ac_aux_dir=
for ac_dir in tclconfig "$srcdir"/tclconfig; do
  if test -f "$ac_dir/install-sh"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install-sh -c"
    break
  elif test -f "$ac_dir/install.sh"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install.sh -c"
    break
  elif test -f "$ac_dir/shtool"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/shtool install -c"
    break
  fi
done
if test -z "$ac_aux_dir"; then
  as_fn_error $? "cannot find install-sh, install.sh, or shtool in tclconfig \"$srcdir\"/tclconfig" "$LINENO" 5
fi

# These three variables are undocumented and unsupported,
# and are intended to be withdrawn in a future Autoconf release.
# They can cause serious problems if a builder's source tree is in a directory
# whose full name contains unusual characters.
ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.



#--------------------------------------------------------------------
# Load the tclConfig.sh file
#--------------------------------------------------------------------


................................................................................








#--------------------------------------------------------------------
# Load the tkConfig.sh file if necessary (Tk extension)
#--------------------------------------------------------------------

#TEA_PATH_TKCONFIG
#TEA_LOAD_TKCONFIG

#--------------------------------------------------------------------
# Load the tclooConfig.sh file on Tcl versions where oo is an
# extension.
#--------------------------------------------------------------------

if test "${TCL_MAJOR_VERSION}" -lt 8 ; then
    as_fn_error $? "${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6 or newer.
Found configuration for Tcl ${TCL_VERSION}." "$LINENO" 5
fi
if test "${TCL_MAJOR_VERSION}" -eq 8 ; then
   if test "${TCL_MINOR_VERSION}" -lt 6 ; then
      as_fn_error $? "${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6 or newer.
Found configuration for Tcl ${TCL_VERSION}." "$LINENO" 5
   fi
   TCLOO_CFLAGS=''
fi
TCL_VERSION_REQ=8.6;


    #
    # Ok, lets find the tdbc configuration
    # First, look for one uninstalled.
................................................................................


  fi
fi

    PKG_CFLAGS="$PKG_CFLAGS ${TCLOO_CFLAGS}"



    vars="${tdbc_INCLUDE_SPEC}"
    for i in $vars; do
	PKG_INCLUDES="$PKG_INCLUDES $i"
    done


if test "x${TEA_PLATFORM}" = "xwindows" -a "x${GCC}" != "xyes" ; then

    vars="\"`${CYGPATH} ${tdbc_STUB_LIB_PATH}`\""
    for i in $vars; do
	if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
	    # Convert foo.lib to -lfoo for GCC.  No-op if not *.lib
................................................................................
	    i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'`
	fi
	PKG_LIBS="$PKG_LIBS $i"
    done


fi








    PKG_CFLAGS="$PKG_CFLAGS ${tdbc_CFLAGS}"



    vars=""
    for i in $vars; do
................................................................................
	fi
	PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i"
    done



#--------------------------------------------------------------------

#




# You can add more files to clean if your extension creates any extra

# files by extending CLEANFILES.
# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
#
# A few miscellaneous platform-specific items:
# TEA_ADD_* any platform specific compiler/build info here.
#--------------------------------------------------------------------



#CLEANFILES="$CLEANFILES pkgIndex.tcl"






#--------------------------------------------------------------------
# Choose which headers you need.  Extension authors should try very
# hard to only rely on the Tcl public header files.  Internal headers
# contain private data structures and are subject to change without
# notice.
# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG
#--------------------------------------------------------------------
................................................................................
# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
# link against the non-stubbed Tcl library.  Add Tk too if necessary.
#--------------------------------------------------------------------


$as_echo "#define USE_TCL_STUBS 1" >>confdefs.h





#--------------------------------------------------------------------
# We need the INT2PTR and PTR2INT macros, so make sure that intptr_t
# is defined.
#--------------------------------------------------------------------

for ac_header in stdint.h sys/types.h
................................................................................

































































#--------------------------------------------------------------------
# Determine the name of the tclsh and/or wish executables in the
# Tcl and Tk build directories or the location they were installed
# into. These paths are used to support running test cases only,
# the Makefile should not be making use of these paths to generate
# a pkgIndex.tcl file or anything else at extension build time.
................................................................................

#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
# You may alternatively have a special pkgIndex.tcl.in or other files
# which require substituting th AC variables in.  Include these here.
#--------------------------------------------------------------------

CONFIGURE_OUTPUTS="Makefile pkgIndex.tcl config.cache config.log config.status"


ac_config_files="$ac_config_files Makefile pkgIndex.tcl"

cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
................................................................................
  $ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi




Name change from configure.in to configure.ac.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
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
...
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
...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#!/bin/bash -norc
dnl	This file is an input file used by the GNU "autoconf" program to
dnl	generate the file "configure", which is run during Tcl installation
dnl	to configure the system for the local environment.
#
# RCS: @(#) $Id: configure.in,v 1.47 2007/02/09 19:06:47 hobbs Exp $

#-----------------------------------------------------------------------
# Sample configure.in for Tcl Extensions.  The only places you should
# need to modify this file are marked by the string __CHANGE__
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# Set your package name and version numbers here.
#
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided.  These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
................................................................................

#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------

AC_CONFIG_AUX_DIR(tclconfig)
TEA_INIT([3.9])



#--------------------------------------------------------------------
# Load the tclConfig.sh file
#--------------------------------------------------------------------

TEA_PATH_TCLCONFIG
TEA_LOAD_TCLCONFIG








#--------------------------------------------------------------------
# Load the tclooConfig.sh file on Tcl versions where oo is an
# extension.
#--------------------------------------------------------------------

if test "${TCL_MAJOR_VERSION}" -lt 8 ; then
    AC_MSG_ERROR([${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6 or newer.
Found configuration for Tcl ${TCL_VERSION}.])
fi
if test "${TCL_MAJOR_VERSION}" -eq 8 ; then
  if test "${TCL_MINOR_VERSION}" -lt 6 ; then
    AC_MSG_ERROR([${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6 or newer.
Found configuration for Tcl ${TCL_VERSION}.])
  fi
  TCLOO_CFLAGS=''
fi
TCL_VERSION_REQ=8.6; AC_SUBST(TCL_VERSION_REQ)

TEA_PATH_CONFIG(tdbc)
TEA_LOAD_CONFIG(tdbc)
# The next bit probably ought to be in TEA_LOAD_CONFIG
AC_MSG_WARN([Looking for "${tdbc_BIN_DIR}/Makefile"])
................................................................................
if test "${TCL_MAJOR_VERSION}" -eq 8 ; then
  if test "${TCL_MINOR_VERSION}" -eq 5 ; then
    TEA_ADD_INCLUDES([${TCLOO_INCLUDE_SPEC}])
    TEA_ADD_LIBS([${TCLOO_STUB_LIB_SPEC}])
  fi
fi
TEA_ADD_CFLAGS([${TCLOO_CFLAGS}])

if test "x${TEA_PLATFORM}" = "xwindows" -a "x${GCC}" != "xyes" ; then
    TEA_ADD_LIBS([\"`${CYGPATH} ${tdbc_STUB_LIB_PATH}`\"])
else
    TEA_ADD_LIBS([${tdbc_STUB_LIB_SPEC}])
fi
TEA_ADD_INCLUDES([${tdbc_INCLUDE_SPEC}])
TEA_ADD_CFLAGS([${tdbc_CFLAGS}])
TEA_ADD_STUB_SOURCES()
TEA_ADD_TCL_SOURCES([library/tdbcpostgres.tcl])

#--------------------------------------------------------------------
# A few miscellaneous platform-specific items:
#
# Define a special symbol for Windows (BUILD_sample in this case) so
# that we create the export library with the dll.
#
# Windows creates a few extra files that need to be cleaned up.
# You can add more files to clean if your extension creates any extra
# files.



#

# TEA_ADD_* any platform specific compiler/build info here.
#--------------------------------------------------------------------

# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
#CLEANFILES="$CLEANFILES pkgIndex.tcl"

if test "${TEA_PLATFORM}" = "windows" ; then
    AC_DEFINE(_WIN32)
fi

#--------------------------------------------------------------------
# Choose which headers you need.  Extension authors should try very
# hard to only rely on the Tcl public header files.  Internal headers
# contain private data structures and are subject to change without
# notice.
# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG
#--------------------------------------------------------------------
................................................................................
# Everyone should be linking against the Tcl stub library.  If you
# can't for some reason, remove this definition.  If you aren't using
# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
# link against the non-stubbed Tcl library.  Add Tk too if necessary.
#--------------------------------------------------------------------

AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs])
AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs])

#--------------------------------------------------------------------
# We need the INT2PTR and PTR2INT macros, so make sure that intptr_t
# is defined.
#--------------------------------------------------------------------

AC_CHECK_HEADERS(stdint.h sys/types.h)
................................................................................
#--------------------------------------------------------------------
# This macro generates a line to use when building a library.  It
# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
# and TEA_LOAD_TCLCONFIG macros above.
#--------------------------------------------------------------------

TEA_MAKE_LIB
TEAX_VC_MANIFEST

#--------------------------------------------------------------------
# Determine the name of the tclsh and/or wish executables in the
# Tcl and Tk build directories or the location they were installed
# into. These paths are used to support running test cases only,
# the Makefile should not be making use of these paths to generate
# a pkgIndex.tcl file or anything else at extension build time.
................................................................................

#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
# You may alternatively have a special pkgIndex.tcl.in or other files
# which require substituting th AC variables in.  Include these here.
#--------------------------------------------------------------------

CONFIGURE_OUTPUTS="Makefile pkgIndex.tcl tdbcConfig.sh config.cache config.log config.status"
AC_SUBST(CONFIGURE_OUTPUTS)

AC_CONFIG_FILES([Makefile pkgIndex.tcl])
AC_OUTPUT

# This is a comment added to force the 'execute' permission to update 
# in the Fossil repository.




<
<
<
<
<
<
<







 







<

>
>







>
>
>
>
>
>
>











|
|

|
|







 







>





<





<

<
<
<
<

<
>
>
>

>



<
<


<
<
<
<







 







<







 







<







 







|


|
<
<
<
<
1
2
3
4







5
6
7
8
9
10
11
..
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
...
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
...
175
176
177
178
179
180
181

182
183
184
185
186
187
188
...
229
230
231
232
233
234
235

236
237
238
239
240
241
242
...
246
247
248
249
250
251
252
253
254
255
256




#!/bin/bash -norc
dnl	This file is an input file used by the GNU "autoconf" program to
dnl	generate the file "configure", which is run during Tcl installation
dnl	to configure the system for the local environment.








#-----------------------------------------------------------------------
# Set your package name and version numbers here.
#
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided.  These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
................................................................................

#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------


TEA_INIT([3.9])

AC_CONFIG_AUX_DIR(tclconfig)

#--------------------------------------------------------------------
# Load the tclConfig.sh file
#--------------------------------------------------------------------

TEA_PATH_TCLCONFIG
TEA_LOAD_TCLCONFIG

#--------------------------------------------------------------------
# Load the tkConfig.sh file if necessary (Tk extension)
#--------------------------------------------------------------------

#TEA_PATH_TKCONFIG
#TEA_LOAD_TKCONFIG

#--------------------------------------------------------------------
# Load the tclooConfig.sh file on Tcl versions where oo is an
# extension.
#--------------------------------------------------------------------

if test "${TCL_MAJOR_VERSION}" -lt 8 ; then
    AC_MSG_ERROR([${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6 or newer.
Found configuration for Tcl ${TCL_VERSION}.])
fi
if test "${TCL_MAJOR_VERSION}" -eq 8 ; then
   if test "${TCL_MINOR_VERSION}" -lt 6 ; then
      AC_MSG_ERROR([${PACKAGE_NAME} ${PACKAGE_VERSION} requires Tcl 8.6 or newer.
Found configuration for Tcl ${TCL_VERSION}.])
   fi
   TCLOO_CFLAGS=''
fi
TCL_VERSION_REQ=8.6; AC_SUBST(TCL_VERSION_REQ)

TEA_PATH_CONFIG(tdbc)
TEA_LOAD_CONFIG(tdbc)
# The next bit probably ought to be in TEA_LOAD_CONFIG
AC_MSG_WARN([Looking for "${tdbc_BIN_DIR}/Makefile"])
................................................................................
if test "${TCL_MAJOR_VERSION}" -eq 8 ; then
  if test "${TCL_MINOR_VERSION}" -eq 5 ; then
    TEA_ADD_INCLUDES([${TCLOO_INCLUDE_SPEC}])
    TEA_ADD_LIBS([${TCLOO_STUB_LIB_SPEC}])
  fi
fi
TEA_ADD_CFLAGS([${TCLOO_CFLAGS}])
TEA_ADD_INCLUDES([${tdbc_INCLUDE_SPEC}])
if test "x${TEA_PLATFORM}" = "xwindows" -a "x${GCC}" != "xyes" ; then
    TEA_ADD_LIBS([\"`${CYGPATH} ${tdbc_STUB_LIB_PATH}`\"])
else
    TEA_ADD_LIBS([${tdbc_STUB_LIB_SPEC}])
fi

TEA_ADD_CFLAGS([${tdbc_CFLAGS}])
TEA_ADD_STUB_SOURCES()
TEA_ADD_TCL_SOURCES([library/tdbcpostgres.tcl])

#--------------------------------------------------------------------

#




# You can add more files to clean if your extension creates any extra

# files by extending CLEANFILES.
# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
#
# A few miscellaneous platform-specific items:
# TEA_ADD_* any platform specific compiler/build info here.
#--------------------------------------------------------------------



#CLEANFILES="$CLEANFILES pkgIndex.tcl"





#--------------------------------------------------------------------
# Choose which headers you need.  Extension authors should try very
# hard to only rely on the Tcl public header files.  Internal headers
# contain private data structures and are subject to change without
# notice.
# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG
#--------------------------------------------------------------------
................................................................................
# Everyone should be linking against the Tcl stub library.  If you
# can't for some reason, remove this definition.  If you aren't using
# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
# link against the non-stubbed Tcl library.  Add Tk too if necessary.
#--------------------------------------------------------------------

AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs])


#--------------------------------------------------------------------
# We need the INT2PTR and PTR2INT macros, so make sure that intptr_t
# is defined.
#--------------------------------------------------------------------

AC_CHECK_HEADERS(stdint.h sys/types.h)
................................................................................
#--------------------------------------------------------------------
# This macro generates a line to use when building a library.  It
# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
# and TEA_LOAD_TCLCONFIG macros above.
#--------------------------------------------------------------------

TEA_MAKE_LIB


#--------------------------------------------------------------------
# Determine the name of the tclsh and/or wish executables in the
# Tcl and Tk build directories or the location they were installed
# into. These paths are used to support running test cases only,
# the Makefile should not be making use of these paths to generate
# a pkgIndex.tcl file or anything else at extension build time.
................................................................................

#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
# You may alternatively have a special pkgIndex.tcl.in or other files
# which require substituting th AC variables in.  Include these here.
#--------------------------------------------------------------------

CONFIGURE_OUTPUTS="Makefile pkgIndex.tcl config.cache config.log config.status"
AC_SUBST(CONFIGURE_OUTPUTS)

AC_OUTPUT([Makefile pkgIndex.tcl])




Changes to doc/tdbc_postgres.n.

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
new database connection.. See \fBtdbc::connection(n)\fR for the
details of how to use the connection to manipulate a database.
.SH "CONNECTION OPTIONS"
.PP
The \fBtdbc::postgres::connection create\fR object command supports the
\fB-encoding\fR, \fB-isolation\fR, \fB-readonly\fR and \fB-timeout\fR
options common to all TDBC drivers. The \fB-timeout\fR option will
only affect connection process, once connected this value will be 
ignored and cannot be changed after connecting. 
.PP
In addition, the following options are recognized (these options must be
set on the initial creation of the connection; they cannot be changed
after connecting) :
.IP "\fB-host\fR \fIhostname\fR"
Connects to the host specified by \fIhostname\fR. Default is to connect using a local Unix domain socket.
.IP "\fB-hostaddr\fR \fIaddress\fR"
Connects to the host specified by given IP \fIaddress\fR. If both \fB-host\fR and \fB-hostaddr\fR are given, the value 
of \fB-host\fR is ignored. Default is to connect using a local Unix domain socket. 
.IP "\fB-port\fR \fInumber\fR"
Connects to a Postgres server listening on the port specified by \fInumber\fR.
It is used only when \fIhost\fR  or \fIhostaddr\fR is specified.
.IP "\fB-user\fR \fIname\fR"
Presents \fIname\fR as the user name to the Postgres server. Default is the
current user ID.
.IP "\fB-passwd\fR \fIpassword\fR"
.IP "\fB-password\fR \fIpassword\fR"
These two options are synonymous. They present the given \fIpassword\fR as 
the user's password to the Postgres server. Default is not to present a password. 
.IP "\fB-database\fR \fIname\fR"
.IP "\fB-db\fR \fIname\fR"
These two options are synonymous.  They present the given \fIname\fR as the
name of the default database to use in Postgres queries. If not specified,
the default database for the current user is used.
.IP "\fB-options\fR \fIopts\fR"
This sets \fIopts\fR as additional command line options send to the server.
................................................................................
.IP "\fB-tty\fR \fIfile\fR"
This option is ignored on never servers. Formerly this specified where to send debug
output. This option is left for compatibility with older servers.
.IP "\fB-sslmode\fR \fImode\fR"
This option determines whether or with what priority an SSL connection will be negotiated with
the server. There are four \fImodes\fR: \fBdisable\fR will attempt only an unencrypted SSL connection;
\fBallow\fR will negotiate, trying first a non-SSL connection, then if that fails, trying an SSL
connection; \fBprefer\fR (the default) will negotiate, trying first an SSL connection, 
then if that fails, trying a regular non-SSL connection; \fBrequire\fR will try only an SSL connection.
If PostgreSQL is compiled without SSL support, using option \fBrequire\fR will cause an error,
and options \fBallow\fR and \fBprefer\fR will be tolerated but the driver will be unable to negotiate
an SSL connection.
.IP \fB-requiressl\fR \fIflag\fR
This option is deprecated in favor of the \fB-sslmode\fR setting. 
The \fIflag\fR value must be a Boolean value. If it is \fBtrue\fR (or
any equivalent), driver will then refuse to connect if the server does
not accept an SSL connection. The default value is \fBfalse\fR (or any
equivalent), and acts the same like \fB-sslmode\fR \fBpreffered\fR
.IP \fB-service\fR \fIname\fR
It specifies a service \fIname\fR in pg_service.conf file that holds additional connection parameters.
This allows applications to specify only a service name so connection parameters can be







|
|







|
|








|
|







 







|





|







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
new database connection.. See \fBtdbc::connection(n)\fR for the
details of how to use the connection to manipulate a database.
.SH "CONNECTION OPTIONS"
.PP
The \fBtdbc::postgres::connection create\fR object command supports the
\fB-encoding\fR, \fB-isolation\fR, \fB-readonly\fR and \fB-timeout\fR
options common to all TDBC drivers. The \fB-timeout\fR option will
only affect connection process, once connected this value will be
ignored and cannot be changed after connecting.
.PP
In addition, the following options are recognized (these options must be
set on the initial creation of the connection; they cannot be changed
after connecting) :
.IP "\fB-host\fR \fIhostname\fR"
Connects to the host specified by \fIhostname\fR. Default is to connect using a local Unix domain socket.
.IP "\fB-hostaddr\fR \fIaddress\fR"
Connects to the host specified by given IP \fIaddress\fR. If both \fB-host\fR and \fB-hostaddr\fR are given, the value
of \fB-host\fR is ignored. Default is to connect using a local Unix domain socket.
.IP "\fB-port\fR \fInumber\fR"
Connects to a Postgres server listening on the port specified by \fInumber\fR.
It is used only when \fIhost\fR  or \fIhostaddr\fR is specified.
.IP "\fB-user\fR \fIname\fR"
Presents \fIname\fR as the user name to the Postgres server. Default is the
current user ID.
.IP "\fB-passwd\fR \fIpassword\fR"
.IP "\fB-password\fR \fIpassword\fR"
These two options are synonymous. They present the given \fIpassword\fR as
the user's password to the Postgres server. Default is not to present a password.
.IP "\fB-database\fR \fIname\fR"
.IP "\fB-db\fR \fIname\fR"
These two options are synonymous.  They present the given \fIname\fR as the
name of the default database to use in Postgres queries. If not specified,
the default database for the current user is used.
.IP "\fB-options\fR \fIopts\fR"
This sets \fIopts\fR as additional command line options send to the server.
................................................................................
.IP "\fB-tty\fR \fIfile\fR"
This option is ignored on never servers. Formerly this specified where to send debug
output. This option is left for compatibility with older servers.
.IP "\fB-sslmode\fR \fImode\fR"
This option determines whether or with what priority an SSL connection will be negotiated with
the server. There are four \fImodes\fR: \fBdisable\fR will attempt only an unencrypted SSL connection;
\fBallow\fR will negotiate, trying first a non-SSL connection, then if that fails, trying an SSL
connection; \fBprefer\fR (the default) will negotiate, trying first an SSL connection,
then if that fails, trying a regular non-SSL connection; \fBrequire\fR will try only an SSL connection.
If PostgreSQL is compiled without SSL support, using option \fBrequire\fR will cause an error,
and options \fBallow\fR and \fBprefer\fR will be tolerated but the driver will be unable to negotiate
an SSL connection.
.IP \fB-requiressl\fR \fIflag\fR
This option is deprecated in favor of the \fB-sslmode\fR setting.
The \fIflag\fR value must be a Boolean value. If it is \fBtrue\fR (or
any equivalent), driver will then refuse to connect if the server does
not accept an SSL connection. The default value is \fBfalse\fR (or any
equivalent), and acts the same like \fB-sslmode\fR \fBpreffered\fR
.IP \fB-service\fR \fIname\fR
It specifies a service \fIname\fR in pg_service.conf file that holds additional connection parameters.
This allows applications to specify only a service name so connection parameters can be

Changes to generic/fakepq.h.

37
38
39
40
41
42
43
44
45
46
typedef void (*PQnoticeProcessor)(void*, const PGresult*);

#define PG_DIAG_SQLSTATE 'C'
#define PG_DIAG_MESSAGE_PRIMARY 'M'

#include "pqStubs.h"

MODULE_SCOPE pqStubDefs* pqStubs;

#endif







|


37
38
39
40
41
42
43
44
45
46
typedef void (*PQnoticeProcessor)(void*, const PGresult*);

#define PG_DIAG_SQLSTATE 'C'
#define PG_DIAG_MESSAGE_PRIMARY 'M'

#include "pqStubs.h"

MODULE_SCOPE const pqStubDefs* pqStubs;

#endif

Changes to generic/pqStubDefs.txt.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# not subject to copyright, under the doctrines of scenes a faire and
# of the merger of idea and expression.  Accordingly, this file is in
# the public domain.
#
#-----------------------------------------------------------------------------

* STUBSTRUCT: pqStubs
* LIBRARY: libpq

const char* pg_encoding_to_char(int);
void PQclear(PGresult*);
int PQclientEncoding(const PGconn*);
char* PQcmdTuples(PGresult*);
PGconn* PQconnectdb(const char*);
char* PQerrorMessage(const PGconn*);







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# not subject to copyright, under the doctrines of scenes a faire and
# of the merger of idea and expression.  Accordingly, this file is in
# the public domain.
#
#-----------------------------------------------------------------------------

* STUBSTRUCT: pqStubs
* LIBRARY: pq

const char* pg_encoding_to_char(int);
void PQclear(PGresult*);
int PQclientEncoding(const PGconn*);
char* PQcmdTuples(PGresult*);
PGconn* PQconnectdb(const char*);
char* PQerrorMessage(const PGconn*);

Changes to generic/pqStubInit.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
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
..
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
...
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
/*
 * pqStubInit.c --
 *
 *	Stubs tables for the foreign PostgreSQL libraries so that
 *	Tcl extensions can use them without the linker's knowing about them.
 *
 * @CREATED@ 2011-04-12 02:23:01Z by genExtStubs.tcl from ../generic/pqStubDefs.txt
 *
 * Copyright (c) 2010 by Kevin B. Kenny.
 *
 * Please refer to the file, 'license.terms' for the conditions on
 * redistribution of this file and for a DISCLAIMER OF ALL WARRANTIES.
 *
 *-----------------------------------------------------------------------------
................................................................................
#include "fakepq.h"

/*
 * Static data used in this file
 */

/*
 * ABI version numbers of the PostgreSQL API that we can cope with.
 */

static const char *const pqSuffixes[] = {
    "", ".5", NULL
};

/*
 * Names of the libraries that might contain the PostgreSQL API
 */




static const char *const pqStubLibNames[] = {
    /* @LIBNAMES@: DO NOT EDIT THESE NAMES */
    "libpq", NULL
    /* @END@ */
};

/*





 * Names of the functions that we need from PostgreSQL
 */

static const char *const pqSymbolNames[] = {
    /* @SYMNAMES@: DO NOT EDIT THESE NAMES */
    "pg_encoding_to_char",
    "PQclear",
    "PQclientEncoding",
    "PQcmdTuples",
................................................................................
};

/*
 * Table containing pointers to the functions named above.
 */

static pqStubDefs pqStubsTable;
pqStubDefs* pqStubs = &pqStubsTable;

/*
 *-----------------------------------------------------------------------------
 *
 * PQInitStubs --
 *
 *	Initialize the Stubs table for the PostgreSQL API
................................................................................
    shlibext = Tcl_GetObjResult(interp);
    Tcl_IncrRefCount(shlibext);

    /* Walk the list of possible library names to find an PostgreSQL client */

    status = TCL_ERROR;
    for (i = 0; status == TCL_ERROR && pqStubLibNames[i] != NULL; ++i) {
	for (j = 0; status == TCL_ERROR && pqSuffixes[j] != NULL; ++j) {
	    path = Tcl_NewStringObj(pqStubLibNames[i], -1);







	    Tcl_AppendObjToObj(path, shlibext);

	    Tcl_AppendToObj(path, pqSuffixes[j], -1);

	    Tcl_IncrRefCount(path);

	    /* Try to load a client library and resolve symbols within it. */

	    Tcl_ResetResult(interp);
	    status = Tcl_LoadFile(interp, path, pqSymbolNames, 0,
			      (void*)pqStubs, &handle);
	    Tcl_DecrRefCount(path);
	}
    }

    /* 
     * Either we've successfully loaded a library (status == TCL_OK), 
     * or we've run out of library names (in which case status==TCL_ERROR
     * and the error message reflects the last unsuccessful load attempt).
     */
    Tcl_DecrRefCount(shlibext);
    if (status != TCL_OK) {
	return NULL;
    }
    return handle;
}






|







 







|


|
|
<
<
<
<
<
>
>
>



|



|
>
>
>
>
>
|
<







 







|







 







|
|
>
>
>
>
>
>
>

>

>






|




|
|









1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
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
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
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
165
166
167
168
169
/*
 * pqStubInit.c --
 *
 *	Stubs tables for the foreign PostgreSQL libraries so that
 *	Tcl extensions can use them without the linker's knowing about them.
 *
 * @CREATED@ 2015-06-26 12:55:15Z by genExtStubs.tcl from ../generic/pqStubDefs.txt
 *
 * Copyright (c) 2010 by Kevin B. Kenny.
 *
 * Please refer to the file, 'license.terms' for the conditions on
 * redistribution of this file and for a DISCLAIMER OF ALL WARRANTIES.
 *
 *-----------------------------------------------------------------------------
................................................................................
#include "fakepq.h"

/*
 * Static data used in this file
 */

/*
 * Names of the libraries that might contain the PostgreSQL API
 */

#if defined(__CYGWIN__) && !defined(LIBPREFIX)
# define LIBPREFIX "cyg"





#else
# define LIBPREFIX "lib"
#endif

static const char *const pqStubLibNames[] = {
    /* @LIBNAMES@: DO NOT EDIT THESE NAMES */
    "pq", NULL
    /* @END@ */
};

/* ABI Version numbers of the PostgreSQL API that we can cope with */

static const char pqSuffixes[][4] = {
    "", ".5"
};

/* Names of the functions that we need from PostgreSQL */


static const char *const pqSymbolNames[] = {
    /* @SYMNAMES@: DO NOT EDIT THESE NAMES */
    "pg_encoding_to_char",
    "PQclear",
    "PQclientEncoding",
    "PQcmdTuples",
................................................................................
};

/*
 * Table containing pointers to the functions named above.
 */

static pqStubDefs pqStubsTable;
const pqStubDefs* pqStubs = &pqStubsTable;

/*
 *-----------------------------------------------------------------------------
 *
 * PQInitStubs --
 *
 *	Initialize the Stubs table for the PostgreSQL API
................................................................................
    shlibext = Tcl_GetObjResult(interp);
    Tcl_IncrRefCount(shlibext);

    /* Walk the list of possible library names to find an PostgreSQL client */

    status = TCL_ERROR;
    for (i = 0; status == TCL_ERROR && pqStubLibNames[i] != NULL; ++i) {
	for (j = 0; status == TCL_ERROR && (j < sizeof(pqSuffixes)/sizeof(pqSuffixes[0])); ++j) {
	    path = Tcl_NewStringObj(LIBPREFIX, -1);
	    Tcl_AppendToObj(path, pqStubLibNames[i], -1);
#ifdef __CYGWIN__
	    if (*pqSuffixes[j]) {
		Tcl_AppendToObj(path, "-", -1);
		Tcl_AppendToObj(path, pqSuffixes[j]+1, -1);
	    }
#endif
	    Tcl_AppendObjToObj(path, shlibext);
#ifndef __CYGWIN__
	    Tcl_AppendToObj(path, pqSuffixes[j], -1);
#endif
	    Tcl_IncrRefCount(path);

	    /* Try to load a client library and resolve symbols within it. */

	    Tcl_ResetResult(interp);
	    status = Tcl_LoadFile(interp, path, pqSymbolNames, 0,
			      &pqStubsTable, &handle);
	    Tcl_DecrRefCount(path);
	}
    }

    /*
     * Either we've successfully loaded a library (status == TCL_OK),
     * or we've run out of library names (in which case status==TCL_ERROR
     * and the error message reflects the last unsuccessful load attempt).
     */
    Tcl_DecrRefCount(shlibext);
    if (status != TCL_OK) {
	return NULL;
    }
    return handle;
}

Changes to generic/pqStubs.h.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
78
79
80
81
82
83
84
85
 *-----------------------------------------------------------------------------
 *
 * ../generic/pqStubs.h --
 *
 *	Stubs for procedures in pqStubDefs.txt
 *
 * Generated by genExtStubs.tcl: DO NOT EDIT
 * 2011-04-12 02:23:01Z
 *
 *-----------------------------------------------------------------------------
 */

typedef struct pqStubDefs {

    /* Functions from libraries: libpq */

    const char* (*pg_encoding_to_charPtr)(int);
    void (*PQclearPtr)(PGresult*);
    int (*PQclientEncodingPtr)(const PGconn*);
    char* (*PQcmdTuplesPtr)(PGresult*);
    PGconn* (*PQconnectdbPtr)(const char*);
    char* (*PQerrorMessagePtr)(const PGconn*);
................................................................................
#define PQresultErrorField (pqStubs->PQresultErrorFieldPtr)
#define PQresultStatus (pqStubs->PQresultStatusPtr)
#define PQsetClientEncoding (pqStubs->PQsetClientEncodingPtr)
#define PQsetNoticeProcessor (pqStubs->PQsetNoticeProcessorPtr)
#define PQstatus (pqStubs->PQstatusPtr)
#define PQuser (pqStubs->PQuserPtr)
#define PQtty (pqStubs->PQttyPtr)
MODULE_SCOPE pqStubDefs *pqStubs;







|






|







 







|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
78
79
80
81
82
83
84
85
 *-----------------------------------------------------------------------------
 *
 * ../generic/pqStubs.h --
 *
 *	Stubs for procedures in pqStubDefs.txt
 *
 * Generated by genExtStubs.tcl: DO NOT EDIT
 * 2015-06-26 12:55:15Z
 *
 *-----------------------------------------------------------------------------
 */

typedef struct pqStubDefs {

    /* Functions from libraries: pq */

    const char* (*pg_encoding_to_charPtr)(int);
    void (*PQclearPtr)(PGresult*);
    int (*PQclientEncodingPtr)(const PGconn*);
    char* (*PQcmdTuplesPtr)(PGresult*);
    PGconn* (*PQconnectdbPtr)(const char*);
    char* (*PQerrorMessagePtr)(const PGconn*);
................................................................................
#define PQresultErrorField (pqStubs->PQresultErrorFieldPtr)
#define PQresultStatus (pqStubs->PQresultStatusPtr)
#define PQsetClientEncoding (pqStubs->PQsetClientEncodingPtr)
#define PQsetNoticeProcessor (pqStubs->PQsetNoticeProcessorPtr)
#define PQstatus (pqStubs->PQstatusPtr)
#define PQuser (pqStubs->PQuserPtr)
#define PQtty (pqStubs->PQttyPtr)
MODULE_SCOPE const pqStubDefs *pqStubs;

Changes to generic/tdbcpostgres.c.

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
...
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
...
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
...
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
...
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
...
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
....
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
....
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
....
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
....
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
....
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
....
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
....
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
....
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
....
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
....
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
....
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
....
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
....
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
....
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
....
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
....
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
....
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
....
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
....
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
....
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
....
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
....
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
....
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
....
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
....
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
....
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
....
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
....
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
....
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
....
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
....
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
....
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
....
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
....
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
....
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
....
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
....
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
....
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
....
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
....
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
....
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
....
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
....
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
....
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
....
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
typedef struct PostgresDataType {
    const char* name;		/* Type name */
    Oid oid;			/* Type number */
} PostgresDataType;
static const PostgresDataType dataTypes[] = {
    { "NULL",	    UNTYPEDOID},
    { "smallint",   INT2OID },
    { "integer",    INT4OID }, 
    { "tinyint",    INT2OID },
    { "float",	    FLOAT8OID },
    { "real",	    FLOAT4OID },
    { "double",	    FLOAT8OID },
    { "timestamp",  TIMESTAMPOID },
    { "bigint",	    INT8OID },
    { "date",	    DATEOID },
................................................................................
};

/* Locations of the string options in the string array */

enum OptStringIndex {
    INDX_HOST, INDX_HOSTA, INDX_PORT, INDX_DB, INDX_USER,
    INDX_PASS, INDX_OPT, INDX_TTY, INDX_SERV, INDX_TOUT,
    INDX_SSLM, INDX_RSSL, INDX_KERB, 
    INDX_MAX
};

/* Names of string options for Postgres PGconnectdb() */

static const char *const optStringNames[] = {
    "host", "hostaddr", "port", "dbname", "user",
    "password", "options", "tty", "service", "connect_timeout", 
    "sslmode", "requiressl", "krbsrvname"
};

/* Flags in the configuration table */

#define CONN_OPT_FLAG_MOD 0x1	/* Configuration value changable at runtime */
#define CONN_OPT_FLAG_ALIAS 0x2	/* Configuration option is an alias */

/* 
 * Relay functions to allow Stubbed functions in the configuration options
 * table.
 */

static char* _PQdb(const PGconn* conn) { return PQdb(conn); }
static char* _PQhost(const PGconn* conn) { return PQhost(conn); }
static char* _PQoptions(const PGconn* conn) { return PQoptions(conn); }
................................................................................

/* Table of configuration options */

static const struct {
    const char * name;		    /* Option name */
    enum OptType type;		    /* Option data type */
    int info;		    	    /* Option index or flag value */
    int flags;			    /* Flags - modifiable; SSL related; 
				     * is an alias */
    char *(*queryF)(const PGconn*); /* Function used to determine the 
				     * option value */
} ConnOptions [] = {
    { "-host",	   TYPE_STRING,    INDX_HOST,	0,		     _PQhost},
    { "-hostaddr", TYPE_STRING,    INDX_HOSTA,	0,		     _PQhost},
    { "-port",	   TYPE_PORT,      INDX_PORT,	0,		     _PQport},
    { "-database", TYPE_STRING,    INDX_DB,	0,		     _PQdb},
    { "-db",	   TYPE_STRING,    INDX_DB,	CONN_OPT_FLAG_ALIAS, _PQdb},
................................................................................
    do {					\
	PerInterpData* _pidata = x;		\
	if ((--(_pidata->refCount)) <= 0) {	\
	    DeletePerInterpData(_pidata);	\
	}					\
    } while(0)

/* 
 * Structure that carries the data for a Postgres connection
 *
 * 	This structure is reference counted, to enable deferring its
 *	destruction until the last statement or result set that refers
 *	to it is destroyed.
 */

................................................................................
 */

typedef struct StatementData {
    int refCount;		/* Reference count */
    ConnectionData* cdata;	/* Data for the connection to which this
				 * statement pertains. */
    Tcl_Obj* subVars;	        /* List of variables to be substituted, in the
				 * order in which they appear in the 
				 * statement */
    Tcl_Obj* nativeSql;		/* Native SQL statement to pass into
				 * Postgres */
    char* stmtName;		/* Name identyfing the statement */
    Tcl_Obj* columnNames;	/* Column names in the result set */
    
    struct ParamData *params;	/* Attributes of parameters */
    int nParams;		/* Number of parameters */
    Oid* paramDataTypes;	/* Param data types list */
    int paramTypesChanged;	/* Indicator of changed param types */
    int flags;
} StatementData;
#define IncrStatementRefCount(x)		\
................................................................................
				/* version */
    "paramtype",		/* name */
    StatementParamtypeMethod,	/* callProc */
    NULL,			/* deleteProc */
    NULL			/* cloneProc */
};

/* 
 * Methods to create on the statement class. 
 */

const static Tcl_MethodType* StatementMethods[] = {
    &StatementParamsMethodType,
    &StatementParamtypeMethodType,
    NULL
};
................................................................................
 *	Executes given query.
 *
 * Results:
 *	TCL_OK on success or the error was non fatal otherwise TCL_ERROR .
 *
 * Side effects:
 *	Sets the interpreter result and error code appropiately to
 *	query execution process. Optionally, when res parameter is 
 *	not NULL and the execution is successful, it returns the
 *	PGResult * struct by this parameter. This struct should be
 *	freed with PQclear() when no longer needed.
 *
 *-----------------------------------------------------------------------------
 */

................................................................................
    const char * query,		/* Query to execute */
    PGresult** resOut		/* Optional handle to result struct */
) {
    PGresult * res; 		/* Query result */

    /* Execute the query */

    res = PQexec(pgPtr, query); 

    /* Return error if the query was unsuccessful */

    if (res == NULL) {
	TransferPostgresError(interp, pgPtr);
	return TCL_ERROR;
    }
................................................................................
    if (resOut != NULL) {
	*resOut = res;
    } else {
	PQclear(res);
    }
    return TCL_OK;
}
     
/*
 *-----------------------------------------------------------------------------
 *
 * TransferPostgresError --
 *
 *	Obtains the connection related error message from the Postgres
 *	client library and transfers them into the Tcl interpreter.
................................................................................
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * TransferPostgresError --
 *
 *	Check if there is any error related to given PGresult object. 
 *	If there was an error, it obtains error message, SQL state
 *	and error number from the Postgres client library and transfers
 *	thenm into the Tcl interpreter. 
 *
 * Results:
 *	TCL_OK if no error exists or the error was non fatal,
 *	otherwise TCL_ERROR is returned
 *
 * Side effects:
 *
 *	Sets the interpreter result and error code to describe the SQL 
 *	connection error.
 *
 *-----------------------------------------------------------------------------
 */

static int TransferResultError(
    Tcl_Interp* interp,
................................................................................
	if (error == PGRES_EMPTY_QUERY) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj("empty query", -1));
	} else {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
		PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY), -1));
	}
    }
    if (error == PGRES_BAD_RESPONSE 
	|| error == PGRES_EMPTY_QUERY
	|| error == PGRES_FATAL_ERROR) {
	return TCL_ERROR;
    } else {
	return TCL_OK; 
    }
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * DeterminePostgresMajorVersion --
................................................................................

    /* Suppress attempts to query the password */
    if (ConnOptions[optionNum].info == INDX_PASS) {
	return Tcl_NewObj();
    }
    if (ConnOptions[optionNum].type == TYPE_ENCODING) {
	value = (char* )pg_encoding_to_char(PQclientEncoding(cdata->pgPtr));
	return Tcl_NewStringObj(value, -1); 
    }

    if (ConnOptions[optionNum].type == TYPE_ISOLATION) {
	if (cdata->isolation == ISOL_NONE) {
	    PGresult * res; 
	    char * isoName;
	    int i = 0; 

	    /* The isolation level wasn't set - get default value */

	    if (ExecSimpleQuery(interp, cdata->pgPtr,
		    "SHOW default_transaction_isolation", &res) != TCL_OK) {
		return NULL;
	    }
	    value = PQgetvalue(res, 0, 0); 
	    isoName = (char*) ckalloc(strlen(value) + 1);
	    strcpy(isoName, value);
	    PQclear(res);

	    /* get rid of space */

	    while (isoName[i] != ' ' && isoName[i] != '\0') {
		i+=1; 
	    }
	    if (isoName[i] == ' ') {
		while (isoName[i] != '\0') {
		    isoName[i] = isoName[i+1];
		    i+=1;
		}
	    }

	    /* Search for isolation level name in predefined table */

	    i=0; 
	    while (TclIsolationLevels[i] != NULL
		   && strcmp(isoName, TclIsolationLevels[i])) {
		i += 1; 
	    }
	    ckfree(isoName);
	    if (TclIsolationLevels[i] != NULL) {
		cdata->isolation = i; 
	    } else {
		return NULL;
	    }
	}
	return Tcl_NewStringObj(
		TclIsolationLevels[cdata->isolation], -1);
    }
................................................................................
	    ConnOptions[optionNum].info != -1) {
	/* Fallback: get value saved ealier */
	value = cdata->savedOpts[ConnOptions[optionNum].info];
	if (value != NULL) {
	    return Tcl_NewStringObj(value, -1);
	}
    }
    return literals[LIT_EMPTY]; 
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ConfigureConnection --
 *
................................................................................
ConfigureConnection(
    ConnectionData* cdata,	/* Connection data */
    Tcl_Interp* interp,		/* Tcl interpreter */
    int objc,			/* Parameter count */
    Tcl_Obj* const objv[],	/* Parameter data */
    int skip			/* Number of parameters to skip */
) {
    int optionIndex;		/* Index of the current option in 
				 * ConnOptions */
    int optionValue;		/* Integer value of the current option */
    int i,j;
    char portval[10];		/* String representation of port number */
    char * encoding = NULL;	/* Selected encoding name */
    int isolation = ISOL_NONE;	/* Isolation level */
    int readOnly = -1;		/* Read only indicator */
#define CONNINFO_LEN 1000
    char connInfo[CONNINFO_LEN]; /* Configuration string for PQconnectdb() */ 

    Tcl_Obj* retval;
    Tcl_Obj* optval;
    int vers;			/* PostgreSQL major version */

    if (cdata->pgPtr != NULL) {

................................................................................
	if (cdata->pgPtr != NULL && !(ConnOptions[optionIndex].flags
					 & CONN_OPT_FLAG_MOD)) {
	    Tcl_Obj* msg = Tcl_NewStringObj("\"", -1);
	    Tcl_AppendObjToObj(msg, objv[i]);
	    Tcl_AppendToObj(msg, "\" option cannot be changed dynamically",
			    -1);
	    Tcl_SetObjResult(interp, msg);
	    Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HY000", 
			     "POSTGRES", "-1", NULL);
	    return TCL_ERROR;
	}

	/* Record option value */

	switch (ConnOptions[optionIndex].type) {
................................................................................
		return TCL_ERROR;
	    }
	    break;
	}
    }

    if (cdata->pgPtr == NULL) {
	j=0; 
	connInfo[0] = '\0'; 
	for (i=0; i<INDX_MAX; i+=1) {
	    if (cdata->savedOpts[i] != NULL ) {
		/* TODO escape values */
		strncpy(&connInfo[j], optStringNames[i], CONNINFO_LEN - j);
		j+=strlen(optStringNames[i]);
		strncpy(&connInfo[j], " = '", CONNINFO_LEN - j);
		j+=strlen(" = '"); 
		strncpy(&connInfo[j], cdata->savedOpts[i], CONNINFO_LEN - j);
		j+=strlen(cdata->savedOpts[i]);
		strncpy(&connInfo[j], "' ", CONNINFO_LEN - j);
		j+=strlen("' ");
	    }
	}
	cdata->pgPtr = PQconnectdb(connInfo);
	if (cdata->pgPtr == NULL) {
	    Tcl_SetObjResult(interp,
			     Tcl_NewStringObj("PQconnectdb() failed, "
					      "propably out of memory.", -1));
	    Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HY001", 
			     "POSTGRES", "NULL", NULL);
	    return TCL_ERROR;
	}

	if (PQstatus(cdata->pgPtr) != CONNECTION_OK) { 
	    TransferPostgresError(interp, cdata->pgPtr);
	    return TCL_ERROR; 
	}
	PQsetNoticeProcessor(cdata->pgPtr, DummyNoticeProcessor, NULL);
    }

    /* Character encoding */

    if (encoding != NULL ) {
	if (PQsetClientEncoding(cdata->pgPtr, encoding) != 0) {
	    TransferPostgresError(interp, cdata->pgPtr);
	    return TCL_ERROR; 
	}
    }

    /* Transaction isolation level */

    if (isolation != ISOL_NONE) {
	if (ExecSimpleQuery(interp, cdata->pgPtr,
................................................................................
	cdata->isolation = isolation;
    }

    /* Readonly indicator */

    if (readOnly != -1) {
	if (readOnly == 0) {
	    if (ExecSimpleQuery(interp, cdata->pgPtr, 
			"SET TRANSACTION READ WRITE", NULL) != TCL_OK) {
		return TCL_ERROR;
	    }
	} else {
	    if (ExecSimpleQuery(interp, cdata->pgPtr, 
			"SET TRANSACTION READ ONLY", NULL) != TCL_OK) {
		return TCL_ERROR;
	    }

	}
	cdata->readOnly = readOnly; 
    }

    /* Determine the PostgreSQL version in use */

    if (DeterminePostgresMajorVersion(interp, cdata, &vers) != TCL_OK) {
	return TCL_ERROR;
    }

    /* 
     * On PostgreSQL 9.0 and later, change 'bytea_output' to the
     * backward-compatible 'escape' setting, so that the code in
     * ResultSetNextrowMethod will retrieve byte array values correctly
     * on either 8.x or 9.x servers.
     */
    if (vers >= 9) {
	if (ExecSimpleQuery(interp, cdata->pgPtr,
................................................................................
    cdata->pgPtr = NULL;
    cdata->stmtCounter = 0;
    cdata->flags = 0;
    cdata->isolation = ISOL_NONE;
    cdata->readOnly = 0;
    IncrPerInterpRefCount(pidata);
    Tcl_ObjectSetMetadata(thisObject, &connectionDataType, (ClientData) cdata);
    
    /* Configure the connection */

    if (ConfigureConnection(cdata, interp, objc, objv, skip) != TCL_OK) {
	return TCL_ERROR;
    }

    return TCL_OK;
................................................................................
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ConnectionBegintransactionMethod --
 *
 *	Method that requests that following operations on an POSTGRES 
 *	connection be executed as an atomic transaction.
 *
 * Usage:
 *	$connection begintransaction
 *
 * Parameters:
 *	None.
................................................................................
	Tcl_SetObjResult(interp, Tcl_NewStringObj("Postgres does not support "
						  "nested transactions", -1));
	Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HYC00",
			 "POSTGRES", "-1", NULL);
	return TCL_ERROR;
    }
   cdata->flags |= CONN_FLAG_IN_XCN;
    
   /* Execute begin trasnaction block command */

   return ExecSimpleQuery(interp, cdata->pgPtr, "BEGIN", NULL);
}
 
/*
 *-----------------------------------------------------------------------------
................................................................................
 * ConnectionCommitMethod --
 *
 *	Method that requests that a pending transaction against a database
 * 	be committed.
 *
 * Usage:
 *	$connection commit
 * 
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns an empty Tcl result if successful, and throws an error
 *	otherwise.
 *
................................................................................
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext);
				/* The current connection object */
    ConnectionData* cdata = (ConnectionData*)
	Tcl_ObjectGetMetadata(thisObject, &connectionDataType);
				/* Instance data */
    
    /* Check parameters */

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 2, objv, "");
	return TCL_ERROR;
    }

................................................................................
						  "progress", -1));
	Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HY010",
			 "POSTGRES", "-1", NULL);
	return TCL_ERROR;
    }

    cdata->flags &= ~ CONN_FLAG_IN_XCN;
    
    /* Execute commit SQL command */
    return ExecSimpleQuery(interp, cdata->pgPtr, "COMMIT", NULL);
}
 
/*
 *-----------------------------------------------------------------------------
 *
................................................................................
 * ConnectionColumnsMethod --
 *
 *	Method that asks for the names of columns in a table
 *	in the database (optionally matching a given pattern)
 *
 * Usage:
 * 	$connection columns table ?pattern?
 * 
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns the list of tables
 *
 *-----------------------------------------------------------------------------
................................................................................
				/* Literal pool */
    PGresult* res,* resType;	/* Results of libpq call */
    char* columnName;		/* Name of the column */
    Oid typeOid;		/* Oid of column type */
    Tcl_Obj* retval;		/* List of table names */
    Tcl_Obj* attrs;		/* Attributes of the column */
    Tcl_Obj* name;		/* Name of a column */
    Tcl_Obj* sqlQuery = Tcl_NewStringObj("SELECT * FROM ", -1); 
				/* Query used */

    Tcl_IncrRefCount(sqlQuery);

    /* Check parameters */

    if (objc < 3 || objc > 4) {
................................................................................
    sqlQuery = Tcl_NewStringObj("SELECT "
	"  column_name,"
	"  numeric_precision,"
	"  character_maximum_length,"
	"  numeric_scale,"
	"  is_nullable"
	"  FROM information_schema.columns"
	"  WHERE table_name='", -1); 
    Tcl_IncrRefCount(sqlQuery);
    Tcl_AppendObjToObj(sqlQuery, objv[2]);
    
    if (objc == 4) {
	Tcl_AppendToObj(sqlQuery,"' AND column_name LIKE '", -1);
	Tcl_AppendObjToObj(sqlQuery, objv[3]);
    }
    Tcl_AppendToObj(sqlQuery,"'", -1);

    if (ExecSimpleQuery(interp, cdata->pgPtr,
................................................................................
	    columnName = PQgetvalue(res, i, 0);
	    name = Tcl_NewStringObj(columnName, -1);

	    Tcl_DictObjPut(NULL, attrs, literals[LIT_NAME], name);

	    /* Get the type name, by retrieving type oid */

	    j = PQfnumber(resType, columnName); 
	    if (j >= 0) {
		typeOid = PQftype(resType, j);

		/* TODO: bsearch or sthing */
		j = 0 ;
		while (dataTypes[j].name != NULL
		       && dataTypes[j].oid != typeOid) {
		    j+=1; 
		}
		if ( dataTypes[j].name != NULL) {
		    Tcl_DictObjPut(NULL, attrs, literals[LIT_TYPE],
				   Tcl_NewStringObj(dataTypes[j].name, -1));
		}
	    }

	    /* 1 is numeric_precision column number */

	    if (!PQgetisnull(res, i, 1)) {
		Tcl_DictObjPut(NULL, attrs, literals[LIT_PRECISION], 
			Tcl_NewStringObj(PQgetvalue(res, i, 1), -1));
	    } else {
		
		/* 2 is character_maximum_length column number */  

		if (!PQgetisnull(res, i, 2)) {
		    Tcl_DictObjPut(NULL, attrs, literals[LIT_PRECISION], 
			    Tcl_NewStringObj(PQgetvalue(res, i, 2), -1));
		}
	    }

	    /* 3 is character_maximum_length column number */

	    if (!PQgetisnull(res, i, 3)) {
		
		/* This is for numbers */
		
		Tcl_DictObjPut(NULL, attrs, literals[LIT_SCALE], 
			Tcl_NewStringObj(PQgetvalue(res, i, 3), -1));
	    }
	    
	    /* 4 is is_nullable column number */
	    
	    Tcl_DictObjPut(NULL, attrs, literals[LIT_NULLABLE],
		    Tcl_NewIntObj(strcmp("YES",
			    PQgetvalue(res, i, 4)) == 0));
	    Tcl_DictObjPut(NULL, retval, name, attrs);
	}

	Tcl_DecrRefCount(sqlQuery);
................................................................................
 *	Other options supported by the constructor are here in read-only
 *	mode; any attempt to change them will result in an error.
 *
 *-----------------------------------------------------------------------------
 */

static int ConnectionConfigureMethod(
     ClientData clientData, 
     Tcl_Interp* interp,
     Tcl_ObjectContext objectContext,
     int objc, 
     Tcl_Obj *const objv[]
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext);
				/* The current connection object */
    int skip = Tcl_ObjectContextSkippedArgs(objectContext);
				/* Number of arguments to skip */
    ConnectionData* cdata = (ConnectionData*)
................................................................................
 * ConnectionRollbackMethod --
 *
 *	Method that requests that a pending transaction against a database
 * 	be rolled back.
 *
 * Usage:
 * 	$connection rollback
 * 
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns an empty Tcl result if successful, and throws an error
 *	otherwise.
 *
................................................................................
 * ConnectionTablesMethod --
 *
 *	Method that asks for the names of tables in the database (optionally
 *	matching a given pattern
 *
 * Usage:
 * 	$connection tables ?pattern?
 * 
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns the list of tables
 *
 *-----------------------------------------------------------------------------
................................................................................
    ConnectionData* cdata = (ConnectionData*)
	Tcl_ObjectGetMetadata(thisObject, &connectionDataType);
				/* Instance data */
    Tcl_Obj** literals = cdata->pidata->literals;
				/* Literal pool */
    PGresult* res;		/* Result of libpq call */
    char * field;		/* Field value from SQL result */
    Tcl_Obj* retval;		/* List of table names */    
    Tcl_Obj* sqlQuery = Tcl_NewStringObj("SELECT tablename"
					 " FROM pg_tables"
					 " WHERE  schemaname = 'public'",
					 -1); 
				/* SQL query for table list */
    int i; 
    Tcl_IncrRefCount(sqlQuery);

    /* Check parameters */

    if (objc < 2 || objc > 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "");
	return TCL_ERROR;
    }

    if (objc == 3) {
	
	/* Pattern string is given */

	Tcl_AppendToObj(sqlQuery, " AND  tablename LIKE '", -1);
	Tcl_AppendObjToObj(sqlQuery, objv[2]);
	Tcl_AppendToObj(sqlQuery, "'", -1);
    }
    
    /* Retrieve the table list */

    if (ExecSimpleQuery(interp, cdata ->pgPtr, Tcl_GetString(sqlQuery),
			&res) != TCL_OK) {
	Tcl_DecrRefCount(sqlQuery);
	return TCL_ERROR;
    }
    Tcl_DecrRefCount(sqlQuery);

    /* Iterate through the tuples and make the Tcl result */

    retval = Tcl_NewObj();
    for (i = 0; i < PQntuples(res); i+=1) {
	if (!PQgetisnull(res, i, 0)) { 
	    field = PQgetvalue(res, i, 0); 
	    if (field) {
		Tcl_ListObjAppendElement(NULL, retval,
			Tcl_NewStringObj(field, -1));
		Tcl_ListObjAppendElement(NULL, retval, literals[LIT_EMPTY]);
	    }
	}
    }
................................................................................
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * DeleteConnectionMetadata, DeleteConnection --
 *
 *	Cleans up when a database connection is deleted.  
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Terminates the connection and frees all system resources associated
 *	with it.
................................................................................
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * UnallocateStatement --
 *
 *	Tries tu unallocate prepared statement using SQL query. No 
 *	errors are reported on failure.
 *
 * Results:
 *	Nothing.
 *
 *-----------------------------------------------------------------------------
 */
................................................................................
    PGresult* res2;
    int i;

    if (stmtName == NULL) {
	stmtName = sdata->stmtName;
    }

    /* 
     * Prepare the statement. Rather than giving parameter types, try
     * to let PostgreSQL infer all of them.
     */

    nativeSqlStr = Tcl_GetStringFromObj(sdata->nativeSql, &nativeSqlLen);
    res = PQprepare(cdata->pgPtr, stmtName, nativeSqlStr, 0, NULL);
    if (res == NULL) {
................................................................................
static Tcl_Obj*
ResultDescToTcl(
    PGresult* result,		/* Result set description */
    int flags			/* Flags governing the conversion */
) {
    Tcl_Obj* retval = Tcl_NewObj();
    Tcl_HashTable names;	/* Hash table to resolve name collisions */
    char * fieldName; 
    Tcl_InitHashTable(&names, TCL_STRING_KEYS);
    if (result != NULL) {
	unsigned int fieldCount = PQnfields(result);
	unsigned int i;
	char numbuf[16];
	for (i = 0; i < fieldCount; ++i) {
	    int new;
................................................................................

    if (Tcl_ListObjGetElements(interp, tokens, &tokenc, &tokenv) != TCL_OK) {
	goto freeTokens;
    }
    nativeSql = Tcl_NewObj();
    Tcl_IncrRefCount(nativeSql);
    j=0;
    
    for (i = 0; i < tokenc; ++i) {
	tokenStr = Tcl_GetStringFromObj(tokenv[i], &tokenLen);
	
	switch (tokenStr[0]) {
	case '$':
	case ':':
	    /*
	     * A PostgreSQL cast is not a parameter!
	     */
	    if (tokenStr[0] == ':' && tokenStr[1] == tokenStr[0]) {
................................................................................
		Tcl_AppendToObj(nativeSql, tokenStr, tokenLen);
		break;
	    }

	    j+=1;
	    snprintf(tmpstr, 30, "$%d", j);
	    Tcl_AppendToObj(nativeSql, tmpstr, -1);
	    Tcl_ListObjAppendElement(NULL, sdata->subVars, 
				     Tcl_NewStringObj(tokenStr+1, tokenLen-1));
	    break;

	case ';':
	    Tcl_SetObjResult(interp,
			     Tcl_NewStringObj("tdbc::postgres"
					      " does not support semicolons "
					      "in statements", -1));
	    goto freeNativeSql;
	    break; 

	default:
	    Tcl_AppendToObj(nativeSql, tokenStr, tokenLen);
	    break;

	}
    }
................................................................................
    retVal = Tcl_NewObj();
    for (i = 0; i < sdata->nParams; ++i) {
	paramDesc = Tcl_NewObj();
	Tcl_ListObjIndex(NULL, sdata->subVars, i, &paramName);
	Tcl_DictObjPut(NULL, paramDesc, literals[LIT_NAME], paramName);
	switch (sdata->params[i].flags & (PARAM_IN | PARAM_OUT)) {
	case PARAM_IN:
	    Tcl_DictObjPut(NULL, paramDesc, literals[LIT_DIRECTION], 
			   literals[LIT_IN]);
	    break;
	case PARAM_OUT:
	    Tcl_DictObjPut(NULL, paramDesc, literals[LIT_DIRECTION], 
			   literals[LIT_OUT]);
	    break;
	case PARAM_IN | PARAM_OUT:
	    Tcl_DictObjPut(NULL, paramDesc, literals[LIT_DIRECTION], 
			   literals[LIT_INOUT]);
	    break;
	default:
	    break;
	}
	typeHashEntry =
	    Tcl_FindHashEntry(&(pidata->typeNumHash),
................................................................................
	}
	Tcl_DictObjPut(NULL, paramDesc, literals[LIT_PRECISION],
		       Tcl_NewIntObj(sdata->params[i].precision));
	Tcl_DictObjPut(NULL, paramDesc, literals[LIT_SCALE],
		       Tcl_NewIntObj(sdata->params[i].scale));
	Tcl_DictObjPut(NULL, retVal, paramName, paramDesc);
    }
	
    Tcl_SetObjResult(interp, retVal);
    return TCL_OK;
}
 
/*
 *-----------------------------------------------------------------------------
 *
................................................................................
    int i;

    /* Check parameters */

    if (objc < 4) {
	goto wrongNumArgs;
    }
    
    i = 3;
    if (Tcl_GetIndexFromObjStruct(interp, objv[i], directions, 
				  sizeof(directions[0]), "direction",
				  TCL_EXACT, &direction) != TCL_OK) {
	direction = PARAM_IN;
	Tcl_ResetResult(interp);
    } else {
	++i;
    }
................................................................................
    ResultSetData* rdata;	/* THe result set object's data */
    Tcl_Obj* paramNameObj;	/* Name of the current parameter */
    const char* paramName;	/* Name of the current parameter */
    Tcl_Obj* paramValObj;	/* Value of the current parameter */

    const char** paramValues;	/* Table of values */
    int* paramLengths;		/* Table of parameter lengths */
    int* paramFormats;		/* Table of parameter formats 
				 * (binary or string) */
    char* paramNeedsFreeing;	/* Flags for whether a parameter needs
				 * its memory released */
    Tcl_Obj** paramTempObjs;	/* Temporary parameter objects allocated
				 * to canonicalize numeric parameter values */

    PGresult* res;		/* Temporary result */
................................................................................
		return TCL_ERROR;
	    }
	    if (TransferResultError(interp, res) != TCL_OK) {
		PQclear(res);
		return TCL_ERROR;
	    }
	    PQclear(res);
	    sdata->paramTypesChanged = 0; 
	}
    }
    
    paramValues = (const char**) ckalloc(sdata->nParams * sizeof(char* ));
    paramLengths = (int*) ckalloc(sdata->nParams * sizeof(int*)); 
    paramFormats = (int*) ckalloc(sdata->nParams * sizeof(int*)); 
    paramNeedsFreeing = ckalloc(sdata->nParams);
    paramTempObjs = (Tcl_Obj**) ckalloc(sdata->nParams * sizeof(Tcl_Obj*));
    
    memset(paramNeedsFreeing, 0, sdata->nParams);
    for (i = 0; i < sdata->nParams; i++) {
	paramTempObjs[i] = NULL;
    }

    for (i=0; i<sdata->nParams; i++) {
	Tcl_ListObjIndex(NULL, sdata->subVars, i, &paramNameObj);
................................................................................
	    if (Tcl_DictObjGet(interp, objv[skip+1],
			       paramNameObj, &paramValObj) != TCL_OK) {
		goto freeParamTables;
	    }
	} else {
	    /* Param from a variable */

	    paramValObj = Tcl_GetVar2Ex(interp, paramName, NULL, 
					TCL_LEAVE_ERR_MSG);

	}
	/* At this point, paramValObj contains the parameter value */
	if (paramValObj != NULL) {
	    char * bufPtr; 
	    int32_t tmp32;
	    int16_t tmp16;
	    
	    switch (sdata->paramDataTypes[i]) {
	    case INT2OID:
		bufPtr = ckalloc(sizeof(int));
		if (Tcl_GetIntFromObj(interp, paramValObj,
				      (int*) bufPtr) != TCL_OK) {
		    goto freeParamTables;
		}
................................................................................
		paramNeedsFreeing[i] = 1;
		tmp16 = *(int*) bufPtr;
		ckfree(bufPtr);
		*(int16_t*)(paramValues[i])=htons(tmp16);
		paramFormats[i] = 1;
		paramLengths[i] = sizeof(int16_t);
		break;
		
	    case INT4OID:
		bufPtr = ckalloc(sizeof(long));
		if (Tcl_GetLongFromObj(interp, paramValObj,
				       (long*) bufPtr) != TCL_OK) {
		    goto freeParamTables;
		}
		paramValues[i]=ckalloc(sizeof(int32_t));
................................................................................
		paramNeedsFreeing[i] = 1;
		tmp32 = *(long*) bufPtr;
		ckfree(bufPtr);
		*((int32_t*)(paramValues[i]))=htonl(tmp32);
		paramFormats[i] = 1;
		paramLengths[i] = sizeof(int32_t);
		break;
				
		/* 
		 * With INT8, FLOAT4, FLOAT8, and NUMERIC, we will be passing
		 * the parameter as text, but it may not be in a canonical
		 * format, because Tcl will recognize binary, octal, and hex
		 * constants where Postgres will not. Begin by extracting
		 * wide int, float, or bignum from the parameter. If that
		 * succeeds, reconvert the result to text to canonicalize
		 * it, and send that text over.
................................................................................

	    case BYTEAOID:
		paramFormats[i] = 1;
		paramValues[i] =
		    (char*)Tcl_GetByteArrayFromObj(paramValObj,
						   &paramLengths[i]);
		break;
		
	    default:
	    convertString:
		paramFormats[i] = 0;
		paramValues[i] = Tcl_GetStringFromObj(paramValObj,
						      &paramLengths[i]);
		break;
	    }
................................................................................
	} else {
	    paramValues[i] = NULL;
	    paramFormats[i] = 0;
	}
    }

    /* Execute the statement */
    rdata->execResult = PQexecPrepared(cdata->pgPtr, rdata->stmtName, 
				       sdata->nParams, paramValues,
				       paramLengths, paramFormats, 0);
    if (TransferResultError(interp, rdata->execResult) != TCL_OK) {
	goto freeParamTables;
    }

    sdata->columnNames = ResultDescToTcl(rdata->execResult, 0);
................................................................................
    ckfree((char*)paramValues);
    ckfree((char*)paramLengths);
    ckfree((char*)paramFormats);
    ckfree((char*)paramNeedsFreeing);
    ckfree((char*)paramTempObjs);

    return status;
    
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ResultSetColumnsMethod --
 *
................................................................................
    Tcl_Obj* colName;		/* Name of the current column */
    Tcl_Obj* resultRow;		/* Row of the result set under construction */

    int status = TCL_ERROR;	/* Status return from this command */

    char * buffer;		/* buffer containing field value */
    int buffSize;		/* size of buffer containing field value */
    int i; 
    
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "varName");
	return TCL_ERROR;
    }

    /* Check if row counter haven't already rech the last row */
    if (rdata->rowCount >= PQntuples(rdata->execResult)) {
................................................................................
    }

    resultRow = Tcl_NewObj();
    Tcl_IncrRefCount(resultRow);

    /* Retrieve one column at a time. */
    for (i = 0; i < nColumns; ++i) {
	colObj = NULL; 
	if (PQgetisnull(rdata->execResult, rdata->rowCount, i) == 0) { 
	    buffSize = PQgetlength(rdata->execResult, rdata->rowCount, i); 
	    buffer = PQgetvalue(rdata->execResult, rdata->rowCount, i);
	    if (PQftype(rdata->execResult, i) == BYTEAOID) {
		/* 
		 * Postgres returns backslash-escape sequences for
		 * binary data. Substitute them away.
		 */
		Tcl_Obj* toSubst;
		toSubst = Tcl_NewStringObj(buffer, buffSize);
		Tcl_IncrRefCount(toSubst);
		colObj = Tcl_SubstObj(interp, toSubst, TCL_SUBST_BACKSLASHES);
................................................................................
	}

	if (lists) {
	    if (colObj == NULL) {
		colObj = Tcl_NewObj();
	    }
	    Tcl_ListObjAppendElement(NULL, resultRow, colObj);
	} else { 
	    if (colObj != NULL) {
		Tcl_ListObjIndex(NULL, sdata->columnNames, i, &colName);
		Tcl_DictObjPut(NULL, resultRow, colName, colObj);
	    }
	}
    }

    /* Advance to the next row */
    rdata->rowCount += 1; 

    /* Save the row in the given variable */

    if (Tcl_SetVar2Ex(interp, Tcl_GetString(objv[2]), NULL,
		      resultRow, TCL_LEAVE_ERR_MSG) == NULL) {
	goto cleanup;
    }
................................................................................
    DecrResultSetRefCount((ResultSetData*)clientData);
}
static void
DeleteResultSet(
    ResultSetData* rdata	/* Metadata for the result set */
) {
    StatementData* sdata = rdata->sdata;
    
    if (rdata->stmtName != NULL) {
	if (rdata->stmtName != sdata->stmtName) {
	    UnallocateStatement(sdata->cdata->pgPtr, rdata->stmtName);
	    ckfree(rdata->stmtName);
	} else {
	    sdata->flags &= ~ STMT_FLAG_BUSY;
	}
    }
    if (rdata->execResult != NULL) { 
	PQclear(rdata->execResult);
    }
    DecrStatementRefCount(rdata->sdata);
    ckfree((char*)rdata);
}
 
/*
................................................................................
    ClientData* newMetaData	/* Where to put the cloned metadata */
) {
    Tcl_SetObjResult(interp,
		     Tcl_NewStringObj("Postgres result sets are not clonable",
				      -1));
    return TCL_ERROR;
}
     
/*
 *-----------------------------------------------------------------------------
 *
 * ResultSetRowcountMethod --
 *
 *	Returns (if known) the number of rows affected by a Postgres statement.
 *
................................................................................

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 2, objv, "");
	return TCL_ERROR;
    }

    nTuples = PQcmdTuples(rdata->execResult);
    if (strlen(nTuples) == 0) { 
	Tcl_SetObjResult(interp, literals[LIT_0]);
    } else {
	Tcl_SetObjResult(interp,
	    Tcl_NewStringObj(nTuples, -1));
    }
    return TCL_OK;
}
 	
/*
 *-----------------------------------------------------------------------------
 *
 * Tdbcpostgres_Init --
 *
 *	Initializes the TDBC-POSTGRES bridge when this library is loaded.
 *
................................................................................
    Tcl_Interp* interp		/* Tcl interpreter */
) {

    PerInterpData* pidata;	/* Per-interpreter data for this package */
    Tcl_Obj* nameObj;		/* Name of a class or method being looked up */
    Tcl_Object curClassObject;  /* Tcl_Object representing the current class */
    Tcl_Class curClass;		/* Tcl_Class representing the current class */
    int i; 

    if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
	return TCL_ERROR;
    }
    if (TclOOInitializeStubs(interp, "1.0") == NULL) {
	return TCL_ERROR;
    }
................................................................................
	pidata->literals[i] = Tcl_NewStringObj(LiteralValues[i], -1);
	Tcl_IncrRefCount(pidata->literals[i]);
    }
    Tcl_InitHashTable(&(pidata->typeNumHash), TCL_ONE_WORD_KEYS);
    for (i = 0; dataTypes[i].name != NULL; ++i) {
	int new;
	Tcl_HashEntry* entry =
	    Tcl_CreateHashEntry(&(pidata->typeNumHash), 
				INT2PTR(dataTypes[i].oid),
				&new);
	Tcl_Obj* nameObj = Tcl_NewStringObj(dataTypes[i].name, -1);
	Tcl_IncrRefCount(nameObj);
	Tcl_SetHashValue(entry, (ClientData) nameObj);
    }


    /* 
     * Find the connection class, and attach an 'init' method to it.
     */

    nameObj = Tcl_NewStringObj("::tdbc::postgres::connection", -1);
	Tcl_IncrRefCount(nameObj);
    if ((curClassObject = Tcl_GetObjectFromObj(interp, nameObj)) == NULL) {
	Tcl_DecrRefCount(nameObj);
................................................................................
       Tcl_Obj* nameObj = (Tcl_Obj*) Tcl_GetHashValue(entry);
       Tcl_DecrRefCount(nameObj);
   }
   Tcl_DeleteHashTable(&(pidata->typeNumHash));

   for (i = 0; i < LIT__END; ++i) {
       Tcl_DecrRefCount(pidata->literals[i]);
   } 
   ckfree((char *) pidata);

   Tcl_MutexLock(&pgMutex);
   if (--pgRefCount == 0) {
       Tcl_FSUnloadFile(NULL, pgLoadHandle);
       pgLoadHandle = NULL;
   }







|







 







|







|








|







 







|

|







 







|







 







|





|







 







|
|







 







|







 







|







 







|







 







|


|







|







 







|




|







 







|




|

|







|







|










|


|



|







 







|







 







|








|







 







|







 







|
|






|











|




|

|









|







 







|




|





|








|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|


|







 







|







|










|


|
|


|







|

|
|


|

|







 







|


|







 







|







 







|







 







|



|

|










|






|













|
|







 







|







 







|







 







|







 







|







 







|


|







 







|









|







 







|



|



|







 







|







 







|

|







 







|







 







|


|

|
|


|







 







|





|


|







 







|







 







|
|







 







|







 







|







 







|







 







|
|







 







|
|
|


|







 







|








|







 







|








|







 







|







 







|







|







 







|







 







|








|







 







|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
...
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
...
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
...
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
...
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
...
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
....
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
....
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
....
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
....
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
....
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
....
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
....
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
....
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
....
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
....
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
....
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
....
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
....
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
....
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
....
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
....
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
....
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
....
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
....
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
....
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
....
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
....
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
....
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
....
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
....
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
....
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
....
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
....
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
....
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
....
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
....
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
....
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
....
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
....
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
....
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
....
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
....
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
....
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
....
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
....
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
....
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
....
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
....
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
....
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
....
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
typedef struct PostgresDataType {
    const char* name;		/* Type name */
    Oid oid;			/* Type number */
} PostgresDataType;
static const PostgresDataType dataTypes[] = {
    { "NULL",	    UNTYPEDOID},
    { "smallint",   INT2OID },
    { "integer",    INT4OID },
    { "tinyint",    INT2OID },
    { "float",	    FLOAT8OID },
    { "real",	    FLOAT4OID },
    { "double",	    FLOAT8OID },
    { "timestamp",  TIMESTAMPOID },
    { "bigint",	    INT8OID },
    { "date",	    DATEOID },
................................................................................
};

/* Locations of the string options in the string array */

enum OptStringIndex {
    INDX_HOST, INDX_HOSTA, INDX_PORT, INDX_DB, INDX_USER,
    INDX_PASS, INDX_OPT, INDX_TTY, INDX_SERV, INDX_TOUT,
    INDX_SSLM, INDX_RSSL, INDX_KERB,
    INDX_MAX
};

/* Names of string options for Postgres PGconnectdb() */

static const char *const optStringNames[] = {
    "host", "hostaddr", "port", "dbname", "user",
    "password", "options", "tty", "service", "connect_timeout",
    "sslmode", "requiressl", "krbsrvname"
};

/* Flags in the configuration table */

#define CONN_OPT_FLAG_MOD 0x1	/* Configuration value changable at runtime */
#define CONN_OPT_FLAG_ALIAS 0x2	/* Configuration option is an alias */

/*
 * Relay functions to allow Stubbed functions in the configuration options
 * table.
 */

static char* _PQdb(const PGconn* conn) { return PQdb(conn); }
static char* _PQhost(const PGconn* conn) { return PQhost(conn); }
static char* _PQoptions(const PGconn* conn) { return PQoptions(conn); }
................................................................................

/* Table of configuration options */

static const struct {
    const char * name;		    /* Option name */
    enum OptType type;		    /* Option data type */
    int info;		    	    /* Option index or flag value */
    int flags;			    /* Flags - modifiable; SSL related;
				     * is an alias */
    char *(*queryF)(const PGconn*); /* Function used to determine the
				     * option value */
} ConnOptions [] = {
    { "-host",	   TYPE_STRING,    INDX_HOST,	0,		     _PQhost},
    { "-hostaddr", TYPE_STRING,    INDX_HOSTA,	0,		     _PQhost},
    { "-port",	   TYPE_PORT,      INDX_PORT,	0,		     _PQport},
    { "-database", TYPE_STRING,    INDX_DB,	0,		     _PQdb},
    { "-db",	   TYPE_STRING,    INDX_DB,	CONN_OPT_FLAG_ALIAS, _PQdb},
................................................................................
    do {					\
	PerInterpData* _pidata = x;		\
	if ((--(_pidata->refCount)) <= 0) {	\
	    DeletePerInterpData(_pidata);	\
	}					\
    } while(0)

/*
 * Structure that carries the data for a Postgres connection
 *
 * 	This structure is reference counted, to enable deferring its
 *	destruction until the last statement or result set that refers
 *	to it is destroyed.
 */

................................................................................
 */

typedef struct StatementData {
    int refCount;		/* Reference count */
    ConnectionData* cdata;	/* Data for the connection to which this
				 * statement pertains. */
    Tcl_Obj* subVars;	        /* List of variables to be substituted, in the
				 * order in which they appear in the
				 * statement */
    Tcl_Obj* nativeSql;		/* Native SQL statement to pass into
				 * Postgres */
    char* stmtName;		/* Name identyfing the statement */
    Tcl_Obj* columnNames;	/* Column names in the result set */

    struct ParamData *params;	/* Attributes of parameters */
    int nParams;		/* Number of parameters */
    Oid* paramDataTypes;	/* Param data types list */
    int paramTypesChanged;	/* Indicator of changed param types */
    int flags;
} StatementData;
#define IncrStatementRefCount(x)		\
................................................................................
				/* version */
    "paramtype",		/* name */
    StatementParamtypeMethod,	/* callProc */
    NULL,			/* deleteProc */
    NULL			/* cloneProc */
};

/*
 * Methods to create on the statement class.
 */

const static Tcl_MethodType* StatementMethods[] = {
    &StatementParamsMethodType,
    &StatementParamtypeMethodType,
    NULL
};
................................................................................
 *	Executes given query.
 *
 * Results:
 *	TCL_OK on success or the error was non fatal otherwise TCL_ERROR .
 *
 * Side effects:
 *	Sets the interpreter result and error code appropiately to
 *	query execution process. Optionally, when res parameter is
 *	not NULL and the execution is successful, it returns the
 *	PGResult * struct by this parameter. This struct should be
 *	freed with PQclear() when no longer needed.
 *
 *-----------------------------------------------------------------------------
 */

................................................................................
    const char * query,		/* Query to execute */
    PGresult** resOut		/* Optional handle to result struct */
) {
    PGresult * res; 		/* Query result */

    /* Execute the query */

    res = PQexec(pgPtr, query);

    /* Return error if the query was unsuccessful */

    if (res == NULL) {
	TransferPostgresError(interp, pgPtr);
	return TCL_ERROR;
    }
................................................................................
    if (resOut != NULL) {
	*resOut = res;
    } else {
	PQclear(res);
    }
    return TCL_OK;
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * TransferPostgresError --
 *
 *	Obtains the connection related error message from the Postgres
 *	client library and transfers them into the Tcl interpreter.
................................................................................
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * TransferPostgresError --
 *
 *	Check if there is any error related to given PGresult object.
 *	If there was an error, it obtains error message, SQL state
 *	and error number from the Postgres client library and transfers
 *	thenm into the Tcl interpreter.
 *
 * Results:
 *	TCL_OK if no error exists or the error was non fatal,
 *	otherwise TCL_ERROR is returned
 *
 * Side effects:
 *
 *	Sets the interpreter result and error code to describe the SQL
 *	connection error.
 *
 *-----------------------------------------------------------------------------
 */

static int TransferResultError(
    Tcl_Interp* interp,
................................................................................
	if (error == PGRES_EMPTY_QUERY) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj("empty query", -1));
	} else {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
		PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY), -1));
	}
    }
    if (error == PGRES_BAD_RESPONSE
	|| error == PGRES_EMPTY_QUERY
	|| error == PGRES_FATAL_ERROR) {
	return TCL_ERROR;
    } else {
	return TCL_OK;
    }
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * DeterminePostgresMajorVersion --
................................................................................

    /* Suppress attempts to query the password */
    if (ConnOptions[optionNum].info == INDX_PASS) {
	return Tcl_NewObj();
    }
    if (ConnOptions[optionNum].type == TYPE_ENCODING) {
	value = (char* )pg_encoding_to_char(PQclientEncoding(cdata->pgPtr));
	return Tcl_NewStringObj(value, -1);
    }

    if (ConnOptions[optionNum].type == TYPE_ISOLATION) {
	if (cdata->isolation == ISOL_NONE) {
	    PGresult * res;
	    char * isoName;
	    int i = 0;

	    /* The isolation level wasn't set - get default value */

	    if (ExecSimpleQuery(interp, cdata->pgPtr,
		    "SHOW default_transaction_isolation", &res) != TCL_OK) {
		return NULL;
	    }
	    value = PQgetvalue(res, 0, 0);
	    isoName = (char*) ckalloc(strlen(value) + 1);
	    strcpy(isoName, value);
	    PQclear(res);

	    /* get rid of space */

	    while (isoName[i] != ' ' && isoName[i] != '\0') {
		i+=1;
	    }
	    if (isoName[i] == ' ') {
		while (isoName[i] != '\0') {
		    isoName[i] = isoName[i+1];
		    i+=1;
		}
	    }

	    /* Search for isolation level name in predefined table */

	    i=0;
	    while (TclIsolationLevels[i] != NULL
		   && strcmp(isoName, TclIsolationLevels[i])) {
		i += 1;
	    }
	    ckfree(isoName);
	    if (TclIsolationLevels[i] != NULL) {
		cdata->isolation = i;
	    } else {
		return NULL;
	    }
	}
	return Tcl_NewStringObj(
		TclIsolationLevels[cdata->isolation], -1);
    }
................................................................................
	    ConnOptions[optionNum].info != -1) {
	/* Fallback: get value saved ealier */
	value = cdata->savedOpts[ConnOptions[optionNum].info];
	if (value != NULL) {
	    return Tcl_NewStringObj(value, -1);
	}
    }
    return literals[LIT_EMPTY];
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ConfigureConnection --
 *
................................................................................
ConfigureConnection(
    ConnectionData* cdata,	/* Connection data */
    Tcl_Interp* interp,		/* Tcl interpreter */
    int objc,			/* Parameter count */
    Tcl_Obj* const objv[],	/* Parameter data */
    int skip			/* Number of parameters to skip */
) {
    int optionIndex;		/* Index of the current option in
				 * ConnOptions */
    int optionValue;		/* Integer value of the current option */
    int i,j;
    char portval[10];		/* String representation of port number */
    char * encoding = NULL;	/* Selected encoding name */
    int isolation = ISOL_NONE;	/* Isolation level */
    int readOnly = -1;		/* Read only indicator */
#define CONNINFO_LEN 1000
    char connInfo[CONNINFO_LEN]; /* Configuration string for PQconnectdb() */

    Tcl_Obj* retval;
    Tcl_Obj* optval;
    int vers;			/* PostgreSQL major version */

    if (cdata->pgPtr != NULL) {

................................................................................
	if (cdata->pgPtr != NULL && !(ConnOptions[optionIndex].flags
					 & CONN_OPT_FLAG_MOD)) {
	    Tcl_Obj* msg = Tcl_NewStringObj("\"", -1);
	    Tcl_AppendObjToObj(msg, objv[i]);
	    Tcl_AppendToObj(msg, "\" option cannot be changed dynamically",
			    -1);
	    Tcl_SetObjResult(interp, msg);
	    Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HY000",
			     "POSTGRES", "-1", NULL);
	    return TCL_ERROR;
	}

	/* Record option value */

	switch (ConnOptions[optionIndex].type) {
................................................................................
		return TCL_ERROR;
	    }
	    break;
	}
    }

    if (cdata->pgPtr == NULL) {
	j=0;
	connInfo[0] = '\0';
	for (i=0; i<INDX_MAX; i+=1) {
	    if (cdata->savedOpts[i] != NULL ) {
		/* TODO escape values */
		strncpy(&connInfo[j], optStringNames[i], CONNINFO_LEN - j);
		j+=strlen(optStringNames[i]);
		strncpy(&connInfo[j], " = '", CONNINFO_LEN - j);
		j+=strlen(" = '");
		strncpy(&connInfo[j], cdata->savedOpts[i], CONNINFO_LEN - j);
		j+=strlen(cdata->savedOpts[i]);
		strncpy(&connInfo[j], "' ", CONNINFO_LEN - j);
		j+=strlen("' ");
	    }
	}
	cdata->pgPtr = PQconnectdb(connInfo);
	if (cdata->pgPtr == NULL) {
	    Tcl_SetObjResult(interp,
			     Tcl_NewStringObj("PQconnectdb() failed, "
					      "propably out of memory.", -1));
	    Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HY001",
			     "POSTGRES", "NULL", NULL);
	    return TCL_ERROR;
	}

	if (PQstatus(cdata->pgPtr) != CONNECTION_OK) {
	    TransferPostgresError(interp, cdata->pgPtr);
	    return TCL_ERROR;
	}
	PQsetNoticeProcessor(cdata->pgPtr, DummyNoticeProcessor, NULL);
    }

    /* Character encoding */

    if (encoding != NULL ) {
	if (PQsetClientEncoding(cdata->pgPtr, encoding) != 0) {
	    TransferPostgresError(interp, cdata->pgPtr);
	    return TCL_ERROR;
	}
    }

    /* Transaction isolation level */

    if (isolation != ISOL_NONE) {
	if (ExecSimpleQuery(interp, cdata->pgPtr,
................................................................................
	cdata->isolation = isolation;
    }

    /* Readonly indicator */

    if (readOnly != -1) {
	if (readOnly == 0) {
	    if (ExecSimpleQuery(interp, cdata->pgPtr,
			"SET TRANSACTION READ WRITE", NULL) != TCL_OK) {
		return TCL_ERROR;
	    }
	} else {
	    if (ExecSimpleQuery(interp, cdata->pgPtr,
			"SET TRANSACTION READ ONLY", NULL) != TCL_OK) {
		return TCL_ERROR;
	    }

	}
	cdata->readOnly = readOnly;
    }

    /* Determine the PostgreSQL version in use */

    if (DeterminePostgresMajorVersion(interp, cdata, &vers) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * On PostgreSQL 9.0 and later, change 'bytea_output' to the
     * backward-compatible 'escape' setting, so that the code in
     * ResultSetNextrowMethod will retrieve byte array values correctly
     * on either 8.x or 9.x servers.
     */
    if (vers >= 9) {
	if (ExecSimpleQuery(interp, cdata->pgPtr,
................................................................................
    cdata->pgPtr = NULL;
    cdata->stmtCounter = 0;
    cdata->flags = 0;
    cdata->isolation = ISOL_NONE;
    cdata->readOnly = 0;
    IncrPerInterpRefCount(pidata);
    Tcl_ObjectSetMetadata(thisObject, &connectionDataType, (ClientData) cdata);

    /* Configure the connection */

    if (ConfigureConnection(cdata, interp, objc, objv, skip) != TCL_OK) {
	return TCL_ERROR;
    }

    return TCL_OK;
................................................................................
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ConnectionBegintransactionMethod --
 *
 *	Method that requests that following operations on an POSTGRES
 *	connection be executed as an atomic transaction.
 *
 * Usage:
 *	$connection begintransaction
 *
 * Parameters:
 *	None.
................................................................................
	Tcl_SetObjResult(interp, Tcl_NewStringObj("Postgres does not support "
						  "nested transactions", -1));
	Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HYC00",
			 "POSTGRES", "-1", NULL);
	return TCL_ERROR;
    }
   cdata->flags |= CONN_FLAG_IN_XCN;

   /* Execute begin trasnaction block command */

   return ExecSimpleQuery(interp, cdata->pgPtr, "BEGIN", NULL);
}
 
/*
 *-----------------------------------------------------------------------------
................................................................................
 * ConnectionCommitMethod --
 *
 *	Method that requests that a pending transaction against a database
 * 	be committed.
 *
 * Usage:
 *	$connection commit
 *
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns an empty Tcl result if successful, and throws an error
 *	otherwise.
 *
................................................................................
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext);
				/* The current connection object */
    ConnectionData* cdata = (ConnectionData*)
	Tcl_ObjectGetMetadata(thisObject, &connectionDataType);
				/* Instance data */

    /* Check parameters */

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 2, objv, "");
	return TCL_ERROR;
    }

................................................................................
						  "progress", -1));
	Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR", "HY010",
			 "POSTGRES", "-1", NULL);
	return TCL_ERROR;
    }

    cdata->flags &= ~ CONN_FLAG_IN_XCN;

    /* Execute commit SQL command */
    return ExecSimpleQuery(interp, cdata->pgPtr, "COMMIT", NULL);
}
 
/*
 *-----------------------------------------------------------------------------
 *
................................................................................
 * ConnectionColumnsMethod --
 *
 *	Method that asks for the names of columns in a table
 *	in the database (optionally matching a given pattern)
 *
 * Usage:
 * 	$connection columns table ?pattern?
 *
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns the list of tables
 *
 *-----------------------------------------------------------------------------
................................................................................
				/* Literal pool */
    PGresult* res,* resType;	/* Results of libpq call */
    char* columnName;		/* Name of the column */
    Oid typeOid;		/* Oid of column type */
    Tcl_Obj* retval;		/* List of table names */
    Tcl_Obj* attrs;		/* Attributes of the column */
    Tcl_Obj* name;		/* Name of a column */
    Tcl_Obj* sqlQuery = Tcl_NewStringObj("SELECT * FROM ", -1);
				/* Query used */

    Tcl_IncrRefCount(sqlQuery);

    /* Check parameters */

    if (objc < 3 || objc > 4) {
................................................................................
    sqlQuery = Tcl_NewStringObj("SELECT "
	"  column_name,"
	"  numeric_precision,"
	"  character_maximum_length,"
	"  numeric_scale,"
	"  is_nullable"
	"  FROM information_schema.columns"
	"  WHERE table_name='", -1);
    Tcl_IncrRefCount(sqlQuery);
    Tcl_AppendObjToObj(sqlQuery, objv[2]);

    if (objc == 4) {
	Tcl_AppendToObj(sqlQuery,"' AND column_name LIKE '", -1);
	Tcl_AppendObjToObj(sqlQuery, objv[3]);
    }
    Tcl_AppendToObj(sqlQuery,"'", -1);

    if (ExecSimpleQuery(interp, cdata->pgPtr,
................................................................................
	    columnName = PQgetvalue(res, i, 0);
	    name = Tcl_NewStringObj(columnName, -1);

	    Tcl_DictObjPut(NULL, attrs, literals[LIT_NAME], name);

	    /* Get the type name, by retrieving type oid */

	    j = PQfnumber(resType, columnName);
	    if (j >= 0) {
		typeOid = PQftype(resType, j);

		/* TODO: bsearch or sthing */
		j = 0 ;
		while (dataTypes[j].name != NULL
		       && dataTypes[j].oid != typeOid) {
		    j+=1;
		}
		if ( dataTypes[j].name != NULL) {
		    Tcl_DictObjPut(NULL, attrs, literals[LIT_TYPE],
				   Tcl_NewStringObj(dataTypes[j].name, -1));
		}
	    }

	    /* 1 is numeric_precision column number */

	    if (!PQgetisnull(res, i, 1)) {
		Tcl_DictObjPut(NULL, attrs, literals[LIT_PRECISION],
			Tcl_NewStringObj(PQgetvalue(res, i, 1), -1));
	    } else {

		/* 2 is character_maximum_length column number */

		if (!PQgetisnull(res, i, 2)) {
		    Tcl_DictObjPut(NULL, attrs, literals[LIT_PRECISION],
			    Tcl_NewStringObj(PQgetvalue(res, i, 2), -1));
		}
	    }

	    /* 3 is character_maximum_length column number */

	    if (!PQgetisnull(res, i, 3)) {

		/* This is for numbers */

		Tcl_DictObjPut(NULL, attrs, literals[LIT_SCALE],
			Tcl_NewStringObj(PQgetvalue(res, i, 3), -1));
	    }

	    /* 4 is is_nullable column number */

	    Tcl_DictObjPut(NULL, attrs, literals[LIT_NULLABLE],
		    Tcl_NewIntObj(strcmp("YES",
			    PQgetvalue(res, i, 4)) == 0));
	    Tcl_DictObjPut(NULL, retval, name, attrs);
	}

	Tcl_DecrRefCount(sqlQuery);
................................................................................
 *	Other options supported by the constructor are here in read-only
 *	mode; any attempt to change them will result in an error.
 *
 *-----------------------------------------------------------------------------
 */

static int ConnectionConfigureMethod(
     ClientData clientData,
     Tcl_Interp* interp,
     Tcl_ObjectContext objectContext,
     int objc,
     Tcl_Obj *const objv[]
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext);
				/* The current connection object */
    int skip = Tcl_ObjectContextSkippedArgs(objectContext);
				/* Number of arguments to skip */
    ConnectionData* cdata = (ConnectionData*)
................................................................................
 * ConnectionRollbackMethod --
 *
 *	Method that requests that a pending transaction against a database
 * 	be rolled back.
 *
 * Usage:
 * 	$connection rollback
 *
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns an empty Tcl result if successful, and throws an error
 *	otherwise.
 *
................................................................................
 * ConnectionTablesMethod --
 *
 *	Method that asks for the names of tables in the database (optionally
 *	matching a given pattern
 *
 * Usage:
 * 	$connection tables ?pattern?
 *
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns the list of tables
 *
 *-----------------------------------------------------------------------------
................................................................................
    ConnectionData* cdata = (ConnectionData*)
	Tcl_ObjectGetMetadata(thisObject, &connectionDataType);
				/* Instance data */
    Tcl_Obj** literals = cdata->pidata->literals;
				/* Literal pool */
    PGresult* res;		/* Result of libpq call */
    char * field;		/* Field value from SQL result */
    Tcl_Obj* retval;		/* List of table names */
    Tcl_Obj* sqlQuery = Tcl_NewStringObj("SELECT tablename"
					 " FROM pg_tables"
					 " WHERE  schemaname = 'public'",
					 -1);
				/* SQL query for table list */
    int i;
    Tcl_IncrRefCount(sqlQuery);

    /* Check parameters */

    if (objc < 2 || objc > 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "");
	return TCL_ERROR;
    }

    if (objc == 3) {

	/* Pattern string is given */

	Tcl_AppendToObj(sqlQuery, " AND  tablename LIKE '", -1);
	Tcl_AppendObjToObj(sqlQuery, objv[2]);
	Tcl_AppendToObj(sqlQuery, "'", -1);
    }

    /* Retrieve the table list */

    if (ExecSimpleQuery(interp, cdata ->pgPtr, Tcl_GetString(sqlQuery),
			&res) != TCL_OK) {
	Tcl_DecrRefCount(sqlQuery);
	return TCL_ERROR;
    }
    Tcl_DecrRefCount(sqlQuery);

    /* Iterate through the tuples and make the Tcl result */

    retval = Tcl_NewObj();
    for (i = 0; i < PQntuples(res); i+=1) {
	if (!PQgetisnull(res, i, 0)) {
	    field = PQgetvalue(res, i, 0);
	    if (field) {
		Tcl_ListObjAppendElement(NULL, retval,
			Tcl_NewStringObj(field, -1));
		Tcl_ListObjAppendElement(NULL, retval, literals[LIT_EMPTY]);
	    }
	}
    }
................................................................................
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * DeleteConnectionMetadata, DeleteConnection --
 *
 *	Cleans up when a database connection is deleted.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Terminates the connection and frees all system resources associated
 *	with it.
................................................................................
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * UnallocateStatement --
 *
 *	Tries tu unallocate prepared statement using SQL query. No
 *	errors are reported on failure.
 *
 * Results:
 *	Nothing.
 *
 *-----------------------------------------------------------------------------
 */
................................................................................
    PGresult* res2;
    int i;

    if (stmtName == NULL) {
	stmtName = sdata->stmtName;
    }

    /*
     * Prepare the statement. Rather than giving parameter types, try
     * to let PostgreSQL infer all of them.
     */

    nativeSqlStr = Tcl_GetStringFromObj(sdata->nativeSql, &nativeSqlLen);
    res = PQprepare(cdata->pgPtr, stmtName, nativeSqlStr, 0, NULL);
    if (res == NULL) {
................................................................................
static Tcl_Obj*
ResultDescToTcl(
    PGresult* result,		/* Result set description */
    int flags			/* Flags governing the conversion */
) {
    Tcl_Obj* retval = Tcl_NewObj();
    Tcl_HashTable names;	/* Hash table to resolve name collisions */
    char * fieldName;
    Tcl_InitHashTable(&names, TCL_STRING_KEYS);
    if (result != NULL) {
	unsigned int fieldCount = PQnfields(result);
	unsigned int i;
	char numbuf[16];
	for (i = 0; i < fieldCount; ++i) {
	    int new;
................................................................................

    if (Tcl_ListObjGetElements(interp, tokens, &tokenc, &tokenv) != TCL_OK) {
	goto freeTokens;
    }
    nativeSql = Tcl_NewObj();
    Tcl_IncrRefCount(nativeSql);
    j=0;

    for (i = 0; i < tokenc; ++i) {
	tokenStr = Tcl_GetStringFromObj(tokenv[i], &tokenLen);

	switch (tokenStr[0]) {
	case '$':
	case ':':
	    /*
	     * A PostgreSQL cast is not a parameter!
	     */
	    if (tokenStr[0] == ':' && tokenStr[1] == tokenStr[0]) {
................................................................................
		Tcl_AppendToObj(nativeSql, tokenStr, tokenLen);
		break;
	    }

	    j+=1;
	    snprintf(tmpstr, 30, "$%d", j);
	    Tcl_AppendToObj(nativeSql, tmpstr, -1);
	    Tcl_ListObjAppendElement(NULL, sdata->subVars,
				     Tcl_NewStringObj(tokenStr+1, tokenLen-1));
	    break;

	case ';':
	    Tcl_SetObjResult(interp,
			     Tcl_NewStringObj("tdbc::postgres"
					      " does not support semicolons "
					      "in statements", -1));
	    goto freeNativeSql;
	    break;

	default:
	    Tcl_AppendToObj(nativeSql, tokenStr, tokenLen);
	    break;

	}
    }
................................................................................
    retVal = Tcl_NewObj();
    for (i = 0; i < sdata->nParams; ++i) {
	paramDesc = Tcl_NewObj();
	Tcl_ListObjIndex(NULL, sdata->subVars, i, &paramName);
	Tcl_DictObjPut(NULL, paramDesc, literals[LIT_NAME], paramName);
	switch (sdata->params[i].flags & (PARAM_IN | PARAM_OUT)) {
	case PARAM_IN:
	    Tcl_DictObjPut(NULL, paramDesc, literals[LIT_DIRECTION],
			   literals[LIT_IN]);
	    break;
	case PARAM_OUT:
	    Tcl_DictObjPut(NULL, paramDesc, literals[LIT_DIRECTION],
			   literals[LIT_OUT]);
	    break;
	case PARAM_IN | PARAM_OUT:
	    Tcl_DictObjPut(NULL, paramDesc, literals[LIT_DIRECTION],
			   literals[LIT_INOUT]);
	    break;
	default:
	    break;
	}
	typeHashEntry =
	    Tcl_FindHashEntry(&(pidata->typeNumHash),
................................................................................
	}
	Tcl_DictObjPut(NULL, paramDesc, literals[LIT_PRECISION],
		       Tcl_NewIntObj(sdata->params[i].precision));
	Tcl_DictObjPut(NULL, paramDesc, literals[LIT_SCALE],
		       Tcl_NewIntObj(sdata->params[i].scale));
	Tcl_DictObjPut(NULL, retVal, paramName, paramDesc);
    }

    Tcl_SetObjResult(interp, retVal);
    return TCL_OK;
}
 
/*
 *-----------------------------------------------------------------------------
 *
................................................................................
    int i;

    /* Check parameters */

    if (objc < 4) {
	goto wrongNumArgs;
    }

    i = 3;
    if (Tcl_GetIndexFromObjStruct(interp, objv[i], directions,
				  sizeof(directions[0]), "direction",
				  TCL_EXACT, &direction) != TCL_OK) {
	direction = PARAM_IN;
	Tcl_ResetResult(interp);
    } else {
	++i;
    }
................................................................................
    ResultSetData* rdata;	/* THe result set object's data */
    Tcl_Obj* paramNameObj;	/* Name of the current parameter */
    const char* paramName;	/* Name of the current parameter */
    Tcl_Obj* paramValObj;	/* Value of the current parameter */

    const char** paramValues;	/* Table of values */
    int* paramLengths;		/* Table of parameter lengths */
    int* paramFormats;		/* Table of parameter formats
				 * (binary or string) */
    char* paramNeedsFreeing;	/* Flags for whether a parameter needs
				 * its memory released */
    Tcl_Obj** paramTempObjs;	/* Temporary parameter objects allocated
				 * to canonicalize numeric parameter values */

    PGresult* res;		/* Temporary result */
................................................................................
		return TCL_ERROR;
	    }
	    if (TransferResultError(interp, res) != TCL_OK) {
		PQclear(res);
		return TCL_ERROR;
	    }
	    PQclear(res);
	    sdata->paramTypesChanged = 0;
	}
    }

    paramValues = (const char**) ckalloc(sdata->nParams * sizeof(char* ));
    paramLengths = (int*) ckalloc(sdata->nParams * sizeof(int*));
    paramFormats = (int*) ckalloc(sdata->nParams * sizeof(int*));
    paramNeedsFreeing = ckalloc(sdata->nParams);
    paramTempObjs = (Tcl_Obj**) ckalloc(sdata->nParams * sizeof(Tcl_Obj*));

    memset(paramNeedsFreeing, 0, sdata->nParams);
    for (i = 0; i < sdata->nParams; i++) {
	paramTempObjs[i] = NULL;
    }

    for (i=0; i<sdata->nParams; i++) {
	Tcl_ListObjIndex(NULL, sdata->subVars, i, &paramNameObj);
................................................................................
	    if (Tcl_DictObjGet(interp, objv[skip+1],
			       paramNameObj, &paramValObj) != TCL_OK) {
		goto freeParamTables;
	    }
	} else {
	    /* Param from a variable */

	    paramValObj = Tcl_GetVar2Ex(interp, paramName, NULL,
					TCL_LEAVE_ERR_MSG);

	}
	/* At this point, paramValObj contains the parameter value */
	if (paramValObj != NULL) {
	    char * bufPtr;
	    int32_t tmp32;
	    int16_t tmp16;

	    switch (sdata->paramDataTypes[i]) {
	    case INT2OID:
		bufPtr = ckalloc(sizeof(int));
		if (Tcl_GetIntFromObj(interp, paramValObj,
				      (int*) bufPtr) != TCL_OK) {
		    goto freeParamTables;
		}
................................................................................
		paramNeedsFreeing[i] = 1;
		tmp16 = *(int*) bufPtr;
		ckfree(bufPtr);
		*(int16_t*)(paramValues[i])=htons(tmp16);
		paramFormats[i] = 1;
		paramLengths[i] = sizeof(int16_t);
		break;

	    case INT4OID:
		bufPtr = ckalloc(sizeof(long));
		if (Tcl_GetLongFromObj(interp, paramValObj,
				       (long*) bufPtr) != TCL_OK) {
		    goto freeParamTables;
		}
		paramValues[i]=ckalloc(sizeof(int32_t));
................................................................................
		paramNeedsFreeing[i] = 1;
		tmp32 = *(long*) bufPtr;
		ckfree(bufPtr);
		*((int32_t*)(paramValues[i]))=htonl(tmp32);
		paramFormats[i] = 1;
		paramLengths[i] = sizeof(int32_t);
		break;

		/*
		 * With INT8, FLOAT4, FLOAT8, and NUMERIC, we will be passing
		 * the parameter as text, but it may not be in a canonical
		 * format, because Tcl will recognize binary, octal, and hex
		 * constants where Postgres will not. Begin by extracting
		 * wide int, float, or bignum from the parameter. If that
		 * succeeds, reconvert the result to text to canonicalize
		 * it, and send that text over.
................................................................................

	    case BYTEAOID:
		paramFormats[i] = 1;
		paramValues[i] =
		    (char*)Tcl_GetByteArrayFromObj(paramValObj,
						   &paramLengths[i]);
		break;

	    default:
	    convertString:
		paramFormats[i] = 0;
		paramValues[i] = Tcl_GetStringFromObj(paramValObj,
						      &paramLengths[i]);
		break;
	    }
................................................................................
	} else {
	    paramValues[i] = NULL;
	    paramFormats[i] = 0;
	}
    }

    /* Execute the statement */
    rdata->execResult = PQexecPrepared(cdata->pgPtr, rdata->stmtName,
				       sdata->nParams, paramValues,
				       paramLengths, paramFormats, 0);
    if (TransferResultError(interp, rdata->execResult) != TCL_OK) {
	goto freeParamTables;
    }

    sdata->columnNames = ResultDescToTcl(rdata->execResult, 0);
................................................................................
    ckfree((char*)paramValues);
    ckfree((char*)paramLengths);
    ckfree((char*)paramFormats);
    ckfree((char*)paramNeedsFreeing);
    ckfree((char*)paramTempObjs);

    return status;

}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ResultSetColumnsMethod --
 *
................................................................................
    Tcl_Obj* colName;		/* Name of the current column */
    Tcl_Obj* resultRow;		/* Row of the result set under construction */

    int status = TCL_ERROR;	/* Status return from this command */

    char * buffer;		/* buffer containing field value */
    int buffSize;		/* size of buffer containing field value */
    int i;

    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "varName");
	return TCL_ERROR;
    }

    /* Check if row counter haven't already rech the last row */
    if (rdata->rowCount >= PQntuples(rdata->execResult)) {
................................................................................
    }

    resultRow = Tcl_NewObj();
    Tcl_IncrRefCount(resultRow);

    /* Retrieve one column at a time. */
    for (i = 0; i < nColumns; ++i) {
	colObj = NULL;
	if (PQgetisnull(rdata->execResult, rdata->rowCount, i) == 0) {
	    buffSize = PQgetlength(rdata->execResult, rdata->rowCount, i);
	    buffer = PQgetvalue(rdata->execResult, rdata->rowCount, i);
	    if (PQftype(rdata->execResult, i) == BYTEAOID) {
		/*
		 * Postgres returns backslash-escape sequences for
		 * binary data. Substitute them away.
		 */
		Tcl_Obj* toSubst;
		toSubst = Tcl_NewStringObj(buffer, buffSize);
		Tcl_IncrRefCount(toSubst);
		colObj = Tcl_SubstObj(interp, toSubst, TCL_SUBST_BACKSLASHES);
................................................................................
	}

	if (lists) {
	    if (colObj == NULL) {
		colObj = Tcl_NewObj();
	    }
	    Tcl_ListObjAppendElement(NULL, resultRow, colObj);
	} else {
	    if (colObj != NULL) {
		Tcl_ListObjIndex(NULL, sdata->columnNames, i, &colName);
		Tcl_DictObjPut(NULL, resultRow, colName, colObj);
	    }
	}
    }

    /* Advance to the next row */
    rdata->rowCount += 1;

    /* Save the row in the given variable */

    if (Tcl_SetVar2Ex(interp, Tcl_GetString(objv[2]), NULL,
		      resultRow, TCL_LEAVE_ERR_MSG) == NULL) {
	goto cleanup;
    }
................................................................................
    DecrResultSetRefCount((ResultSetData*)clientData);
}
static void
DeleteResultSet(
    ResultSetData* rdata	/* Metadata for the result set */
) {
    StatementData* sdata = rdata->sdata;

    if (rdata->stmtName != NULL) {
	if (rdata->stmtName != sdata->stmtName) {
	    UnallocateStatement(sdata->cdata->pgPtr, rdata->stmtName);
	    ckfree(rdata->stmtName);
	} else {
	    sdata->flags &= ~ STMT_FLAG_BUSY;
	}
    }
    if (rdata->execResult != NULL) {
	PQclear(rdata->execResult);
    }
    DecrStatementRefCount(rdata->sdata);
    ckfree((char*)rdata);
}
 
/*
................................................................................
    ClientData* newMetaData	/* Where to put the cloned metadata */
) {
    Tcl_SetObjResult(interp,
		     Tcl_NewStringObj("Postgres result sets are not clonable",
				      -1));
    return TCL_ERROR;
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * ResultSetRowcountMethod --
 *
 *	Returns (if known) the number of rows affected by a Postgres statement.
 *
................................................................................

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 2, objv, "");
	return TCL_ERROR;
    }

    nTuples = PQcmdTuples(rdata->execResult);
    if (strlen(nTuples) == 0) {
	Tcl_SetObjResult(interp, literals[LIT_0]);
    } else {
	Tcl_SetObjResult(interp,
	    Tcl_NewStringObj(nTuples, -1));
    }
    return TCL_OK;
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * Tdbcpostgres_Init --
 *
 *	Initializes the TDBC-POSTGRES bridge when this library is loaded.
 *
................................................................................
    Tcl_Interp* interp		/* Tcl interpreter */
) {

    PerInterpData* pidata;	/* Per-interpreter data for this package */
    Tcl_Obj* nameObj;		/* Name of a class or method being looked up */
    Tcl_Object curClassObject;  /* Tcl_Object representing the current class */
    Tcl_Class curClass;		/* Tcl_Class representing the current class */
    int i;

    if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
	return TCL_ERROR;
    }
    if (TclOOInitializeStubs(interp, "1.0") == NULL) {
	return TCL_ERROR;
    }
................................................................................
	pidata->literals[i] = Tcl_NewStringObj(LiteralValues[i], -1);
	Tcl_IncrRefCount(pidata->literals[i]);
    }
    Tcl_InitHashTable(&(pidata->typeNumHash), TCL_ONE_WORD_KEYS);
    for (i = 0; dataTypes[i].name != NULL; ++i) {
	int new;
	Tcl_HashEntry* entry =
	    Tcl_CreateHashEntry(&(pidata->typeNumHash),
				INT2PTR(dataTypes[i].oid),
				&new);
	Tcl_Obj* nameObj = Tcl_NewStringObj(dataTypes[i].name, -1);
	Tcl_IncrRefCount(nameObj);
	Tcl_SetHashValue(entry, (ClientData) nameObj);
    }


    /*
     * Find the connection class, and attach an 'init' method to it.
     */

    nameObj = Tcl_NewStringObj("::tdbc::postgres::connection", -1);
	Tcl_IncrRefCount(nameObj);
    if ((curClassObject = Tcl_GetObjectFromObj(interp, nameObj)) == NULL) {
	Tcl_DecrRefCount(nameObj);
................................................................................
       Tcl_Obj* nameObj = (Tcl_Obj*) Tcl_GetHashValue(entry);
       Tcl_DecrRefCount(nameObj);
   }
   Tcl_DeleteHashTable(&(pidata->typeNumHash));

   for (i = 0; i < LIT__END; ++i) {
       Tcl_DecrRefCount(pidata->literals[i]);
   }
   ckfree((char *) pidata);

   Tcl_MutexLock(&pgMutex);
   if (--pgRefCount == 0) {
       Tcl_FSUnloadFile(NULL, pgLoadHandle);
       pgLoadHandle = NULL;
   }

Changes to tests/future/tdbcpostgre.test.tcl.

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
	$stmt paramtype xlongb1 longblob
	$stmt paramtype xtext1 text
	$stmt paramtype xblob1 blob
	$stmt paramtype xvarb1 varbinary
	$stmt paramtype xvarc1 varchar
	$stmt paramtype xbin1 binary 20
	$stmt paramtype xchar1 char 20
    } 
    -body {
	set trouble {}
	set xtiny1 0x14
	set xsmall1 0x3039
	set xint1 0xbc614e
	set xfloat1 1.125
	set xdouble1 1.125







|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
	$stmt paramtype xlongb1 longblob
	$stmt paramtype xtext1 text
	$stmt paramtype xblob1 blob
	$stmt paramtype xvarb1 varbinary
	$stmt paramtype xvarc1 varchar
	$stmt paramtype xbin1 binary 20
	$stmt paramtype xchar1 char 20
    }
    -body {
	set trouble {}
	set xtiny1 0x14
	set xsmall1 0x3039
	set xint1 0xbc614e
	set xfloat1 1.125
	set xdouble1 1.125

Changes to win/makefile.vc.

1
2
3
4
5
6
7
8
9
10
11
12
13
#------------------------------------------------------------- -*- makefile -*-
# makefile.vc --
#
#	Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+)
#
# This makefile is based upon the Tcl 8.6 Makefile.vc and modified to 
# make it suitable as a general package makefile. Look for the word EDIT
# which marks sections that may need modification. As a minumum you will
# need to change the PROJECT, DOTVERSION and DLLOBJS variables to values
# relevant to your package.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.





|







1
2
3
4
5
6
7
8
9
10
11
12
13
#------------------------------------------------------------- -*- makefile -*-
# makefile.vc --
#
#	Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+)
#
# This makefile is based upon the Tcl 8.6 Makefile.vc and modified to
# make it suitable as a general package makefile. Look for the word EDIT
# which marks sections that may need modification. As a minumum you will
# need to change the PROJECT, DOTVERSION and DLLOBJS variables to values
# relevant to your package.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.