sqllogictest

Check-in [5c63a5e855]
Login

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

Overview
Comment:Modified select1.* scripts to work with MS SQL (namely, removing OFFSET/LIMIT clauses); Fixed handle leak in slt_odbc3.c.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5c63a5e8554f48497543cb5b347fb20fe0ca685f
User & Date: shaneh 2008-12-01 14:42:58.000
Context
2008-12-01
20:02
Use a single -odbc CONNSTR command-line argument instead of -engine ODBC3 and -connection CONNSTR. Added hash-threshold and halt record types. Added the OMIT_ODBC compile-time option. check-in: 96bff359ee user: drh tags: trunk
14:42
Modified select1.* scripts to work with MS SQL (namely, removing OFFSET/LIMIT clauses); Fixed handle leak in slt_odbc3.c. check-in: 5c63a5e855 user: shaneh tags: trunk
04:54
Broke out SQLite interface; Added ODBC3 interface; Minor bug fixes. check-in: 86ab9a0ad0 user: shaneh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to proto/select1.proto.

more than 10,000 changes

Changes to proto/select1.tcl.
87
88
89
90
91
92
93


94
95
96
97

98
99
100
101
  if {$m>0} {
    set op [expr {rand()>0.5 ? "\n    OR " : "\n   AND "}]
    set w [lrange [scramble $wexpr] 1 $m]
    append sql "\n WHERE [join $w $op]"
  }
  incr n -1
  append sql "\n ORDER BY [join [scramble [lrange $sequence 0 $n]] ,]"


  append sql "\n LIMIT [expr {int(rand()*5)+1}]"
  if {rand()>0.5} {
   append sql " OFFSET [expr {int(rand()*5)+1}]"
  }

  puts "query [string range $type 0 $n] nosort"
  puts "$sql"
  puts ""
}







>
>
|
|
|
<
>




87
88
89
90
91
92
93
94
95
96
97
98

99
100
101
102
103
  if {$m>0} {
    set op [expr {rand()>0.5 ? "\n    OR " : "\n   AND "}]
    set w [lrange [scramble $wexpr] 1 $m]
    append sql "\n WHERE [join $w $op]"
  }
  incr n -1
  append sql "\n ORDER BY [join [scramble [lrange $sequence 0 $n]] ,]"
  # uncomment below to add LIMIT/OFFSET support.   MS SQL Server doesn't 
  # support this currently.
  #append sql "\n LIMIT [expr {int(rand()*5)+1}]"
  #if {rand()>0.5} {
  # append sql " OFFSET [expr {int(rand()*5)+1}]"

  #}
  puts "query [string range $type 0 $n] nosort"
  puts "$sql"
  puts ""
}
Changes to src/slt_odbc3.c.
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
**
*******************************************************************************
** Here begins the implementation of the ODBC3 DbEngine object.
**
** This DbEngine expects an ODBC3 DSN named 'sqllogictest'
** and a database named 'slt' available through that DSN to exist.
** The DSN should be accessible to the current user.





**
*/
#ifdef WIN32
#include <windows.h>
#endif
#define SQL_NOUNICODEMAP
#include <sql.h>
#include <sqlext.h>


#define SLT_DSN "sqllogictest"
#define SLT_DB  "slt"



/* forward prototypes */

static int ODBC3Statement(
  void *pConn,                /* Connection created by xConnect */
  const char *zSql            /* SQL statement to evaluate */
);


/*
** Structure used to hold handles needed for ODBC3 connection.
*/
typedef struct ODBC3_Handles ODBC3_Handles;
struct ODBC3_Handles {
  SQLHENV env;







>
>
>
>
>














>
|
>




<







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
**
*******************************************************************************
** Here begins the implementation of the ODBC3 DbEngine object.
**
** This DbEngine expects an ODBC3 DSN named 'sqllogictest'
** and a database named 'slt' available through that DSN to exist.
** The DSN should be accessible to the current user.
** On connect, it will attempt to "DROP" all existing tables 
** from the database name 'slt' to reset it to a known status.
**
** The DSN name and DB name are controlled by the defines
** SLT_DSN and SLT_DB.
**
*/
#ifdef WIN32
#include <windows.h>
#endif
#define SQL_NOUNICODEMAP
#include <sql.h>
#include <sqlext.h>


#define SLT_DSN "sqllogictest"
#define SLT_DB  "slt"


/* 
** Forward prototypes.
*/
static int ODBC3Statement(
  void *pConn,                /* Connection created by xConnect */
  const char *zSql            /* SQL statement to evaluate */
);


/*
** Structure used to hold handles needed for ODBC3 connection.
*/
typedef struct ODBC3_Handles ODBC3_Handles;
struct ODBC3_Handles {
  SQLHENV env;
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

256
257
258
259
260
261
262


/*
** This routine is called to open a connection to a new, empty database.
** The zConnectStr argument is the value of the -connection command-line
** option.  This is intended to contain information on how to connect to
** the database engine.  The zConnectStr argument will be NULL if there
** is no -connection on the command-line.  In the case of ODBC3, the
** zConnectStr is the DSN to open.
**
** An object that describes the newly opened and initialized database
** connection is returned by writing into *ppConn.
**
** This routine returns 0 on success and non-zero if there are any errors.
*/
static int ODBC3Connect(
  void *NotUsed,              /* Argument from DbEngine object.  Not used */
  const char *zConnectStr,    /* Connection string */
  void **ppConn               /* Write completed connection here */
){
  int rc = 0;
  SQLRETURN ret; /* ODBC API return status */
  ODBC3_Handles *pODBC3conn = NULL;
  char szSqlConnStr[512];

  /* Allocate a structure to hold all of our ODBC3 handles */
  pODBC3conn = (ODBC3_Handles *)malloc(sizeof(ODBC3_Handles));
  if( !pODBC3conn ){

    return 1;
  }
  pODBC3conn->env = SQL_NULL_HENV;
  pODBC3conn->dbc = SQL_NULL_HDBC;

  /* Allocate an environment handle */
  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &pODBC3conn->env);







|
<



















>







234
235
236
237
238
239
240
241

242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268


/*
** This routine is called to open a connection to a new, empty database.
** The zConnectStr argument is the value of the -connection command-line
** option.  This is intended to contain information on how to connect to
** the database engine.  The zConnectStr argument will be NULL if there
** is no -connection on the command-line.  

**
** An object that describes the newly opened and initialized database
** connection is returned by writing into *ppConn.
**
** This routine returns 0 on success and non-zero if there are any errors.
*/
static int ODBC3Connect(
  void *NotUsed,              /* Argument from DbEngine object.  Not used */
  const char *zConnectStr,    /* Connection string */
  void **ppConn               /* Write completed connection here */
){
  int rc = 0;
  SQLRETURN ret; /* ODBC API return status */
  ODBC3_Handles *pODBC3conn = NULL;
  char szSqlConnStr[512];

  /* Allocate a structure to hold all of our ODBC3 handles */
  pODBC3conn = (ODBC3_Handles *)malloc(sizeof(ODBC3_Handles));
  if( !pODBC3conn ){
    fprintf(stderr, "out of memory at %s:%d\n", __FILE__, __LINE__);
    return 1;
  }
  pODBC3conn->env = SQL_NULL_HENV;
  pODBC3conn->dbc = SQL_NULL_HDBC;

  /* Allocate an environment handle */
  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &pODBC3conn->env);
348
349
350
351
352
353
354

355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377

378
379



380



381

382

383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410

411

412





413
414

415
416
417
418
419
420
421
422
static int ODBC3Query(
  void *pConn,                /* Connection created by xConnect */
  const char *zSql,           /* SQL statement to evaluate */
  const char *zType,          /* One character for each column of result */
  char ***pazResult,          /* RETURN:  Array of result values */
  int *pnResult               /* RETURN:  Number of result values */
){

  SQLRETURN ret; /* ODBC API return status */
  ODBC3_Handles *pODBC3conn = pConn;
  ODBC3_resAccum res;          /* query result accumulator */
  char zBuffer[512];          /* Buffer to render numbers */
  SQLSMALLINT columns;        /* number of columns in result-set */
  SQLHSTMT stmt = SQL_NULL_HSTMT;

  /* zero out accumulator structure */
  memset(&res, 0, sizeof(res));

  /* Allocate a statement handle */
  ret = SQLAllocHandle(SQL_HANDLE_STMT, pODBC3conn->dbc, &stmt);
  if( !SQL_SUCCEEDED(ret) && (ret != SQL_SUCCESS_WITH_INFO) ){
    ODBC3_perror("SQLAllocHandle", pODBC3conn->dbc, SQL_HANDLE_DBC);
    return 1;
  }

  ret = SQLExecDirect(stmt, (SQLCHAR *)zSql, SQL_NTS);
  if( !SQL_SUCCEEDED(ret) && (ret != SQL_SUCCESS_WITH_INFO) ){
    ODBC3_perror("SQLExecDirect", stmt, SQL_HANDLE_STMT);
    return 1;
  }


  /* How many columns are there */
  SQLNumResultCols(stmt, &columns);







  /* Loop through the rows in the result-set */

  while( SQL_SUCCEEDED(ret = SQLFetch(stmt)) ){

      SQLUSMALLINT i;
      /* Loop through the columns */
      for(i = 1; i <= columns; i++){
          SQLINTEGER indicator;
          /* retrieve column data as a string */
          ret = SQLGetData(stmt, 
                           i, 
                           SQL_C_CHAR,
                           zBuffer, 
                           sizeof(zBuffer), 
                           &indicator);
          if( SQL_SUCCEEDED(ret) ){
              char *z;
              /* Handle null columns */
              if( indicator == SQL_NULL_DATA ){ 
                strcpy(zBuffer, "NULL");
              /* Handle empty columns */
              } else if( *zBuffer == '\0' ) {
                strcpy(zBuffer, "(empty)");
              }
              ODBC3_appendValue(&res, zBuffer);
              /* Convert non-printing and control characters to '@' */
              z = res.azValue[res.nUsed-1];
              while( *z ){
                if( *z<' ' || *z>'~' ){ *z = '@'; }
                z++;
              }
          }

      }

  }





  *pazResult = res.azValue;
  *pnResult = res.nUsed;

  return 0;
}


/*
** This interface is called to free the memory that was returned
** by xQuery.
**







>
|

|

















|


>
|
|
>
>
>
|
>
>
>
|
>
|
>
|
|
|









|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

>

>

>
>
>
>
>


>
|







354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
static int ODBC3Query(
  void *pConn,                /* Connection created by xConnect */
  const char *zSql,           /* SQL statement to evaluate */
  const char *zType,          /* One character for each column of result */
  char ***pazResult,          /* RETURN:  Array of result values */
  int *pnResult               /* RETURN:  Number of result values */
){
  int rc = 0;
  SQLRETURN ret;              /* ODBC API return status */
  ODBC3_Handles *pODBC3conn = pConn;
  ODBC3_resAccum res;         /* query result accumulator */
  char zBuffer[512];          /* Buffer to render numbers */
  SQLSMALLINT columns;        /* number of columns in result-set */
  SQLHSTMT stmt = SQL_NULL_HSTMT;

  /* zero out accumulator structure */
  memset(&res, 0, sizeof(res));

  /* Allocate a statement handle */
  ret = SQLAllocHandle(SQL_HANDLE_STMT, pODBC3conn->dbc, &stmt);
  if( !SQL_SUCCEEDED(ret) && (ret != SQL_SUCCESS_WITH_INFO) ){
    ODBC3_perror("SQLAllocHandle", pODBC3conn->dbc, SQL_HANDLE_DBC);
    return 1;
  }

  ret = SQLExecDirect(stmt, (SQLCHAR *)zSql, SQL_NTS);
  if( !SQL_SUCCEEDED(ret) && (ret != SQL_SUCCESS_WITH_INFO) ){
    ODBC3_perror("SQLExecDirect", stmt, SQL_HANDLE_STMT);
    rc = 1;
  }

  if( !rc ){
    /* How many columns are there */
    ret = SQLNumResultCols(stmt, &columns);
    if( !SQL_SUCCEEDED(ret) && (ret != SQL_SUCCESS_WITH_INFO) ){
      ODBC3_perror("SQLNumResultCols", stmt, SQL_HANDLE_STMT);
      rc = 1;
    }
  }
  
  if( !rc ){
    /* Loop through the rows in the result-set */
    do {
      ret = SQLFetch(stmt);
      if( SQL_SUCCEEDED(ret) ){
        SQLUSMALLINT i;
        /* Loop through the columns */
        for(i = 1; i <= columns; i++){
          SQLINTEGER indicator;
          /* retrieve column data as a string */
          ret = SQLGetData(stmt, 
                           i, 
                           SQL_C_CHAR,
                           zBuffer, 
                           sizeof(zBuffer), 
                           &indicator);
          if( SQL_SUCCEEDED(ret) ){
            char *z;
            /* Handle null columns */
            if( indicator == SQL_NULL_DATA ){ 
              strcpy(zBuffer, "NULL");
            /* Handle empty columns */
            } else if( *zBuffer == '\0' ) {
              strcpy(zBuffer, "(empty)");
            }
            ODBC3_appendValue(&res, zBuffer);
            /* Convert non-printing and control characters to '@' */
            z = res.azValue[res.nUsed-1];
            while( *z ){
              if( *z<' ' || *z>'~' ){ *z = '@'; }
              z++;
            }
          }
        } /* end for i */
      }
    } while( SQL_SUCCEEDED(ret) );
  }
  
  if( stmt != SQL_NULL_HSTMT ){
    SQLFreeHandle(SQL_HANDLE_STMT, stmt);
  }

  *pazResult = res.azValue;
  *pnResult = res.nUsed;

  return rc;
}


/*
** This interface is called to free the memory that was returned
** by xQuery.
**
450
451
452
453
454
455
456

457
458
459
460
461
462
463
  void *pConn                 /* Connection created by xConnect */
){
  int rc = 0;
  SQLRETURN ret; /* ODBC API return status */
  ODBC3_Handles *pODBC3conn = pConn;
  
  if ( !pODBC3conn ){

    return 1;
  }

  ret = SQLDisconnect(pODBC3conn->dbc);   /* disconnect from driver */
  if( !SQL_SUCCEEDED(ret) && (ret != SQL_SUCCESS_WITH_INFO) ){
    ODBC3_perror("SQLDisconnect", pODBC3conn->dbc, SQL_HANDLE_DBC);
    rc = 1;







>







474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
  void *pConn                 /* Connection created by xConnect */
){
  int rc = 0;
  SQLRETURN ret; /* ODBC API return status */
  ODBC3_Handles *pODBC3conn = pConn;
  
  if ( !pODBC3conn ){
    fprintf(stderr, "invalid ODBC3 connection object\n");
    return 1;
  }

  ret = SQLDisconnect(pODBC3conn->dbc);   /* disconnect from driver */
  if( !SQL_SUCCEEDED(ret) && (ret != SQL_SUCCESS_WITH_INFO) ){
    ODBC3_perror("SQLDisconnect", pODBC3conn->dbc, SQL_HANDLE_DBC);
    rc = 1;
Changes to test/select1.test.

more than 10,000 changes