tdbc::mysql
Diff
Not logged in

Differences From Artifact [d117eb80ce]:

To Artifact [c75cf33225]:


142
143
144
145
146
147
148
149

150
151
152
153
154
155
156
142
143
144
145
146
147
148

149
150
151
152
153
154
155
156







-
+







	    DeletePerInterpData(_pidata);	\
	}					\
    } while(0)

/*
 * Structure that carries the data for an MYSQL connection
 *
 * 	The ConnectionData structure is refcounted to simplify the
 *	The ConnectionData structure is refcounted to simplify the
 *	destruction of statements associated with a connection.
 *	When a connection is destroyed, the subordinate namespace that
 *	contains its statements is taken down, destroying them. It's
 *	not safe to take down the ConnectionData until nothing is
 *	referring to it, which avoids taking down the hDBC until the
 *	other objects that refer to it vanish.
 */
165
166
167
168
169
170
171
172

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

193
194
195
196
197
198
199
165
166
167
168
169
170
171

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

192
193
194
195
196
197
198
199







-
+



















-
+







} ConnectionData;

/*
 * Flags for the state of an MYSQL connection
 */

#define CONN_FLAG_AUTOCOMMIT	0x1	/* Autocommit is set */
#define CONN_FLAG_IN_XCN	0x2 	/* Transaction is in progress */
#define CONN_FLAG_IN_XCN	0x2	/* Transaction is in progress */
#define CONN_FLAG_INTERACTIVE	0x4	/* -interactive requested at connect */

#define IncrConnectionRefCount(x) \
    do {			  \
	++((x)->refCount);	  \
    } while(0)
#define DecrConnectionRefCount(x)		\
    do {					\
	ConnectionData* conn = x;		\
	if (conn->refCount-- <= 1) {	\
	    DeleteConnection(conn);		\
	}					\
    } while(0)

/*
 * Structure that carries the data for a MySQL prepared statement.
 *
 *	Just as with connections, statements need to defer taking down
 *	their client data until other objects (i.e., result sets) that
 * 	refer to them have had a chance to clean up. Hence, this
 *	refer to them have had a chance to clean up. Hence, this
 *	structure is reference counted as well.
 */

typedef struct StatementData {
    size_t refCount;		/* Reference count */
    ConnectionData* cdata;	/* Data for the connection to which this
				 * statement pertains. */
234
235
236
237
238
239
240
241
242


243
244
245
246
247
248
249
234
235
236
237
238
239
240


241
242
243
244
245
246
247
248
249







-
-
+
+







    int dataType;		/* Data type */
    int precision;		/* Size of the expected data */
    int scale;			/* Digits after decimal point of the
				 * expected data */
} ParamData;

#define PARAM_KNOWN	1<<0	/* Something is known about the parameter */
#define PARAM_IN 	1<<1	/* Parameter is an input parameter */
#define PARAM_OUT 	1<<2	/* Parameter is an output parameter */
#define PARAM_IN	1<<1	/* Parameter is an input parameter */
#define PARAM_OUT	1<<2	/* Parameter is an output parameter */
				/* (Both bits are set if parameter is
				 * an INOUT parameter) */
#define PARAM_BINARY	1<<3	/* Parameter is binary */

/*
 * Structure describing a MySQL result set.  The object that the Tcl
 * API terms a "result set" actually has to be represented by a MySQL
318
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333
334

335
336
337

338
339
340
341
342
343
344
318
319
320
321
322
323
324

325
326
327
328
329
330
331
332
333

334
335
336

337
338
339
340
341
342
343
344







-
+








-
+


-
+







    { "varbinary",	MYSQL_TYPE_VAR_STRING | IS_BINARY },
    { "varchar",	MYSQL_TYPE_VAR_STRING },
    { "varbinary",	MYSQL_TYPE_VARCHAR | IS_BINARY },
    { "varchar",	MYSQL_TYPE_VARCHAR },
    { "binary",		MYSQL_TYPE_STRING | IS_BINARY },
    { "char",		MYSQL_TYPE_STRING },
    { "geometry",	MYSQL_TYPE_GEOMETRY },
    { NULL, 		0 }
    { NULL,		0 }
};

/* Configuration options for MySQL connections */

/* Data types of configuration options */

enum OptType {
    TYPE_STRING,		/* Arbitrary character string */
    TYPE_FLAG, 			/* Boolean flag */
    TYPE_FLAG,			/* Boolean flag */
    TYPE_ENCODING,		/* Encoding name */
    TYPE_ISOLATION,		/* Transaction isolation level */
    TYPE_PORT, 			/* Port number */
    TYPE_PORT,			/* Port number */
    TYPE_READONLY,		/* Read-only indicator */
    TYPE_TIMEOUT		/* Timeout value */
};

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

enum OptStringIndex {
364
365
366
367
368
369
370
371

372
373
374
375
376
377
378
364
365
366
367
368
369
370

371
372
373
374
375
376
377
378







-
+







    int flags;		/* Flags - modifiable; SSL related; is an alias */
    const char* query;	/* How to determine the option value? */
} ConnOptions [] = {
    { "-compress",    TYPE_FLAG,      CLIENT_COMPRESS,	  0,
      "SELECT '', @@SLAVE_COMPRESSED_PROTOCOL" },
    { "-database",    TYPE_STRING,    INDX_DB,		  CONN_OPT_FLAG_MOD,
      "SELECT '', DATABASE();"},
    { "-db",	      TYPE_STRING,    INDX_DB, 		  CONN_OPT_FLAG_MOD
    { "-db",	      TYPE_STRING,    INDX_DB,		  CONN_OPT_FLAG_MOD
							| CONN_OPT_FLAG_ALIAS,
      "SELECT '', DATABASE()" },
    { "-encoding",    TYPE_ENCODING,  0,		  0,
      "SELECT '', 'utf-8'" },
    { "-host",	      TYPE_STRING,    INDX_HOST,	  0,
      "SHOW SESSION VARIABLES WHERE VARIABLE_NAME = 'hostname'" },
    { "-interactive", TYPE_FLAG,      CLIENT_INTERACTIVE, 0,
790
791
792
793
794
795
796
797

798
799
800
801
802
803
804
790
791
792
793
794
795
796

797
798
799
800
801
802
803
804







-
+







 *	Returns a pointer to one of an array of MYSQL_BIND objects
 *
 *-----------------------------------------------------------------------------
 */

static MYSQL_BIND*
MysqlBindIndex(
    MYSQL_BIND* b, 		/* Binding array to alter */
    MYSQL_BIND* b,		/* Binding array to alter */
    Tcl_Size i			/* Index in the binding array */
) {
    if (mysqlClientAtLeast51) {
	return (MYSQL_BIND*)(((struct st_mysql_bind_51*) b) + i);
    } else {
	return (MYSQL_BIND*)(((struct st_mysql_bind_50*) b) + i);
    }
884
885
886
887
888
889
890
891

892
893
894
895
896
897
898
899
900
901
902
903

904
905
906
907
908
909
910
911
912
913
914
915
916

917
918
919
920
921
922
923
924
925
926
927
928

929
930
931
932
933
934
935
936
937
938
939
940
941

942
943
944
945
946
947
948
949
950
951
952
953
954

955
956
957
958
959
960
961
962
963
964
965
966
967

968
969
970
971
972
973
974
884
885
886
887
888
889
890

891
892
893
894
895
896
897
898
899
900
901
902

903
904
905
906
907
908
909
910
911
912
913
914
915

916
917
918
919
920
921
922
923
924
925
926
927

928
929
930
931
932
933
934
935
936
937
938
939
940

941
942
943
944
945
946
947
948
949
950
951
952
953

954
955
956
957
958
959
960
961
962
963
964
965
966

967
968
969
970
971
972
973
974







-
+











-
+












-
+











-
+












-
+












-
+












-
+







 *	Access the fields of a MYSQL_BIND object
 *
 *-----------------------------------------------------------------------------
 */

static void*
MysqlBindGetBuffer(
    MYSQL_BIND* b, 		/* Binding array to alter */
    MYSQL_BIND* b,		/* Binding array to alter */
    Tcl_Size i			/* Index in the binding array */
) {
    if (mysqlClientAtLeast51) {
	return ((struct st_mysql_bind_51*) b)[i].buffer;
    } else {
	return ((struct st_mysql_bind_50*) b)[i].buffer;
    }
}

static unsigned long
MysqlBindGetBufferLength(
    MYSQL_BIND* b, 		/* Binding array to alter */
    MYSQL_BIND* b,		/* Binding array to alter */
    Tcl_Size i			/* Index in the binding array */
) {
    if (mysqlClientAtLeast51) {
	return ((struct st_mysql_bind_51*) b)[i].buffer_length;
    } else {
	return ((struct st_mysql_bind_50*) b)[i].buffer_length;
    }

}

static enum enum_field_types
MysqlBindGetBufferType(
    MYSQL_BIND* b, 		/* Binding array to alter */
    MYSQL_BIND* b,		/* Binding array to alter */
    Tcl_Size i			/* Index in the binding array */
) {
    if (mysqlClientAtLeast51) {
	return ((struct st_mysql_bind_51*) b)[i].buffer_type;
    } else {
	return ((struct st_mysql_bind_50*) b)[i].buffer_type;
    }
}

static void
MysqlBindSetBufferType(
    MYSQL_BIND* b, 		/* Binding array to alter */
    MYSQL_BIND* b,		/* Binding array to alter */
    Tcl_Size i,			/* Index in the binding array */
    enum enum_field_types t	/* Buffer type to assign */
) {
    if (mysqlClientAtLeast51) {
	((struct st_mysql_bind_51*) b)[i].buffer_type = t;
    } else {
	((struct st_mysql_bind_50*) b)[i].buffer_type = t;
    }
}

static void
MysqlBindSetLength(
    MYSQL_BIND* b, 		/* Binding array to alter */
    MYSQL_BIND* b,		/* Binding array to alter */
    Tcl_Size i,			/* Index in the binding array */
    unsigned long* p		/* Length pointer to assign */
) {
    if (mysqlClientAtLeast51) {
	((struct st_mysql_bind_51*) b)[i].length = p;
    } else {
	((struct st_mysql_bind_50*) b)[i].length = p;
    }
}

static void
MysqlBindSetIsNull(
    MYSQL_BIND* b, 		/* Binding array to alter */
    MYSQL_BIND* b,		/* Binding array to alter */
    Tcl_Size i,			/* Index in the binding array */
    my_bool* p			/* "Is null" indicator pointer to assign */
) {
    if (mysqlClientAtLeast51) {
	((struct st_mysql_bind_51*) b)[i].is_null = p;
    } else {
	((struct st_mysql_bind_50*) b)[i].is_null = p;
    }
}

static void
MysqlBindSetError(
    MYSQL_BIND* b, 		/* Binding array to alter */
    MYSQL_BIND* b,		/* Binding array to alter */
    Tcl_Size i,			/* Index in the binding array */
    my_bool* p			/* Error indicator pointer to assign */
) {
    if (mysqlClientAtLeast51) {
	((struct st_mysql_bind_51*) b)[i].error = p;
    } else {
	((struct st_mysql_bind_50*) b)[i].error = p;
1535
1536
1537
1538
1539
1540
1541
1542

1543
1544
1545
1546
1547
1548
1549
1535
1536
1537
1538
1539
1540
1541

1542
1543
1544
1545
1546
1547
1548
1549







-
+







 *
 * 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?
 *	$connection columns table ?pattern?
 *
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns the list of tables
 *
1633
1634
1635
1636
1637
1638
1639
1640

1641
1642
1643
1644
1645
1646
1647
1633
1634
1635
1636
1637
1638
1639

1640
1641
1642
1643
1644
1645
1646
1647







-
+








/*
 *-----------------------------------------------------------------------------
 *
 * ConnectionCommitMethod --
 *
 *	Method that requests that a pending transaction against a database
 * 	be committed.
 *	be committed.
 *
 * Usage:
 *	$connection commit
 *
 * Parameters:
 *	None.
 *
1902
1903
1904
1905
1906
1907
1908
1909

1910
1911
1912

1913
1914
1915
1916
1917
1918
1919
1902
1903
1904
1905
1906
1907
1908

1909
1910
1911

1912
1913
1914
1915
1916
1917
1918
1919







-
+


-
+








/*
 *-----------------------------------------------------------------------------
 *
 * ConnectionRollbackMethod --
 *
 *	Method that requests that a pending transaction against a database
 * 	be rolled back.
 *	be rolled back.
 *
 * Usage:
 * 	$connection rollback
 *	$connection rollback
 *
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns an empty Tcl result if successful, and throws an error
 *	otherwise.
2060
2061
2062
2063
2064
2065
2066
2067

2068
2069
2070
2071
2072
2073
2074
2060
2061
2062
2063
2064
2065
2066

2067
2068
2069
2070
2071
2072
2073
2074







-
+







 *
 * ConnectionTablesMethod --
 *
 *	Method that asks for the names of tables in the database (optionally
 *	matching a given pattern
 *
 * Usage:
 * 	$connection tables ?pattern?
 *	$connection tables ?pattern?
 *
 * Parameters:
 *	None.
 *
 * Results:
 *	Returns the list of tables
 *
2426
2427
2428
2429
2430
2431
2432
2433
2434


2435

2436
2437
2438
2439
2440
2441
2442
2426
2427
2428
2429
2430
2431
2432


2433
2434

2435
2436
2437
2438
2439
2440
2441
2442







-
-
+
+
-
+







 */

static int
StatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    Tcl_Size objc, 			/* Parameter count */
    Tcl_Obj *const *objv	/* Parameter vector */
    Tcl_Size objc,			/* Parameter count */
    Tcl_Obj *const *objv)	/* Parameter vector */
) {
{
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* Number of args to skip before the
				 * payload arguments */
    Tcl_Object connectionObject;
				/* The database connection as a Tcl_Object */
2587
2588
2589
2590
2591
2592
2593
2594

2595
2596
2597
2598
2599
2600
2601
2587
2588
2589
2590
2591
2592
2593

2594
2595
2596
2597
2598
2599
2600
2601







-
+







 */

static int
StatementParamsMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    Tcl_Size objc, 			/* Parameter count */
    Tcl_Size objc,			/* Parameter count */
    Tcl_Obj *const *objv	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    StatementData* sdata	/* The current statement */
	= (StatementData*) Tcl_ObjectGetMetadata(thisObject,
						 &statementDataType);
2675
2676
2677
2678
2679
2680
2681
2682
2683


2684

2685
2686
2687
2688
2689
2690
2691
2692
2693
2694

2695
2696
2697
2698
2699
2700
2701
2675
2676
2677
2678
2679
2680
2681


2682
2683

2684
2685
2686
2687
2688
2689
2690
2691
2692
2693

2694
2695
2696
2697
2698
2699
2700
2701







-
-
+
+
-
+









-
+







 */

static int
StatementParamtypeMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    Tcl_Size objc, 			/* Parameter count */
    Tcl_Obj *const *objv	/* Parameter vector */
    Tcl_Size objc,			/* Parameter count */
    Tcl_Obj *const *objv)	/* Parameter vector */
) {
{
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    StatementData* sdata	/* The current statement */
	= (StatementData*) Tcl_ObjectGetMetadata(thisObject,
						 &statementDataType);
    static const struct {
	const char* name;
	int flags;
    } directions[] = {
	{ "in", 	PARAM_IN },
	{ "in",	PARAM_IN },
	{ "out",	PARAM_OUT },
	{ "inout",	PARAM_IN | PARAM_OUT },
	{ NULL,		0 }
    };
    int direction;
    int typeNum;		/* Data type number of a parameter */
    int precision;		/* Data precision */
2890
2891
2892
2893
2894
2895
2896
2897

2898
2899
2900
2901
2902
2903
2904
2890
2891
2892
2893
2894
2895
2896

2897
2898
2899
2900
2901
2902
2903
2904







-
+







 */

static int
ResultSetConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    Tcl_Size objc, 			/* Parameter count */
    Tcl_Size objc,			/* Parameter count */
    Tcl_Obj *const *objv	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* Number of args to skip */
    Tcl_Object statementObject;	/* The current statement object */
3227
3228
3229
3230
3231
3232
3233
3234

3235
3236
3237
3238
3239
3240
3241
3227
3228
3229
3230
3231
3232
3233

3234
3235
3236
3237
3238
3239
3240
3241







-
+







 */

static int
ResultSetColumnsMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    Tcl_Size objc, 			/* Parameter count */
    Tcl_Size objc,			/* Parameter count */
    Tcl_Obj *const *objv	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);
3280
3281
3282
3283
3284
3285
3286
3287

3288
3289
3290
3291
3292
3293
3294
3280
3281
3282
3283
3284
3285
3286

3287
3288
3289
3290
3291
3292
3293
3294







-
+







 */

static int
ResultSetNextrowMethod(
    void *clientData,	/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    Tcl_Size objc, 			/* Parameter count */
    Tcl_Size objc,			/* Parameter count */
    Tcl_Obj *const *objv	/* Parameter vector */
) {

    int lists = PTR2INT(clientData);
				/* Flag == 1 if lists are to be returned,
				 * 0 if dicts are to be returned */

3464
3465
3466
3467
3468
3469
3470
3471

3472
3473
3474
3475
3476
3477
3478
3464
3465
3466
3467
3468
3469
3470

3471
3472
3473
3474
3475
3476
3477
3478







-
+







 */

static int
ResultSetRowcountMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    Tcl_Size objc, 			/* Parameter count */
    Tcl_Size objc,		/* Parameter count */
    Tcl_Obj *const *objv	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);
				/* Data pertaining to the current result set */