Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix for #3719. When synthesizing a CREATE TABLE statement as as result of a "CREATE TABLE AS", quote the column type names unless they are simple identifiers or simple identifiers followed by one or two dimensions (e.g. "VARCHAR(10)"). (CVS 6345) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
7c6437efe0a0e935cfa8041bd6b94070 |
User & Date: | danielk1977 2009-03-14 08:37:24.000 |
Context
2009-03-16
| ||
10:59 | Remove surplus white space from shell.c. Use strlen30() instead of strlen(). (CVS 6346) (check-in: 324a1aff30 user: drh tags: trunk) | |
2009-03-14
| ||
08:37 | Fix for #3719. When synthesizing a CREATE TABLE statement as as result of a "CREATE TABLE AS", quote the column type names unless they are simple identifiers or simple identifiers followed by one or two dimensions (e.g. "VARCHAR(10)"). (CVS 6345) (check-in: 7c6437efe0 user: danielk1977 tags: trunk) | |
2009-03-13
| ||
15:32 | Do not overrun a buffer in the genfkey code (now part of shell.c). Fix for #3722. (CVS 6344) (check-in: 943b11fb18 user: danielk1977 tags: trunk) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** ** $Id: build.c,v 1.522 2009/03/14 08:37:24 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** This routine is called when a new SQL statement is beginning to ** be parsed. Initialize the pParse structure as needed. */ |
︙ | ︙ | |||
1326 1327 1328 1329 1330 1331 1332 | for(n=0; *z; n++, z++){ if( *z=='"' ){ n++; } } return n + 2; } /* | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | > > | | 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 | for(n=0; *z; n++, z++){ if( *z=='"' ){ n++; } } return n + 2; } /* ** This function is a wrapper around sqlite3GetToken() used by ** isValidDimension(). This function differs from sqlite3GetToken() in ** that: ** ** * Whitespace is ignored, and ** * The output variable *peToken is set to 0 if the end of the ** nul-terminated input string is reached. */ static int getTokenNoSpace(unsigned char *z, int *peToken){ int n = 0; while( sqlite3Isspace(z[n]) ) n++; if( !z[n] ){ *peToken = 0; return 0; } return n + sqlite3GetToken(&z[n], peToken); } /* ** Parameter z points to a nul-terminated string. Return true if, when ** whitespace is ignored, the contents of this string matches one of ** the following patterns: ** ** "" ** "(number)" ** "(number,number)" */ static int isValidDimension(unsigned char *z){ int eToken; int n = 0; n += getTokenNoSpace(&z[n], &eToken); if( eToken ){ if( eToken!=TK_LP ) return 0; n += getTokenNoSpace(&z[n], &eToken); if( eToken==TK_PLUS || eToken==TK_MINUS ){ n += getTokenNoSpace(&z[n], &eToken); } if( eToken!=TK_INTEGER && eToken!=TK_FLOAT ) return 0; n += getTokenNoSpace(&z[n], &eToken); if( eToken==TK_COMMA ){ n += getTokenNoSpace(&z[n], &eToken); if( eToken==TK_PLUS || eToken==TK_MINUS ){ n += getTokenNoSpace(&z[n], &eToken); } if( eToken!=TK_INTEGER && eToken!=TK_FLOAT ) return 0; n += getTokenNoSpace(&z[n], &eToken); } if( eToken!=TK_RP ) return 0; getTokenNoSpace(&z[n], &eToken); } if( eToken ) return 0; return 1; } /* ** The first parameter is a pointer to an output buffer. The second ** parameter is a pointer to an integer that contains the offset at ** which to write into the output buffer. This function copies the ** nul-terminated string pointed to by the third parameter, zSignedIdent, ** to the specified offset in the buffer and updates *pIdx to refer ** to the first byte after the last byte written before returning. ** ** If the string zSignedIdent consists entirely of alpha-numeric ** characters, does not begin with a digit and is not an SQL keyword, ** then it is copied to the output buffer exactly as it is. Otherwise, ** it is quoted using double-quotes. */ static void identPut(char *z, int *pIdx, char *zSignedIdent, int isTypename){ unsigned char *zIdent = (unsigned char*)zSignedIdent; int i, j, needQuote; i = *pIdx; for(j=0; zIdent[j]; j++){ if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break; } needQuote = sqlite3Isdigit(zIdent[0]) || sqlite3KeywordCode(zIdent, j)!=TK_ID; if( !needQuote ){ if( isTypename ){ /* If this is a type-name, allow a little more flexibility. In SQLite, ** a type-name is specified as: ** ** ids [ids] [(number [, number])] ** ** where "ids" is either a quoted string or a simple identifier (in the ** above notation, [] means optional). It is a bit tricky to check ** for all cases, but it is good to avoid unnecessarily quoting common ** typenames like VARCHAR(10). */ needQuote = !isValidDimension(&zIdent[j]); }else{ needQuote = zIdent[j]; } } if( needQuote ) z[i++] = '"'; for(j=0; zIdent[j]; j++){ z[i++] = zIdent[j]; if( zIdent[j]=='"' ) z[i++] = '"'; } if( needQuote ) z[i++] = '"'; z[i] = 0; |
︙ | ︙ | |||
1363 1364 1365 1366 1367 1368 1369 | char *zSep, *zSep2, *zEnd, *z; Column *pCol; n = 0; for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){ n += identLength(pCol->zName); z = pCol->zType; if( z ){ | | | | | < | 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 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 | char *zSep, *zSep2, *zEnd, *z; Column *pCol; n = 0; for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){ n += identLength(pCol->zName); z = pCol->zType; if( z ){ n += identLength(z); } } n += identLength(p->zName); if( n<50 ){ zSep = ""; zSep2 = ","; zEnd = ")"; }else{ zSep = "\n "; zSep2 = ",\n "; zEnd = "\n)"; } n += 35 + 6*p->nCol; zStmt = sqlite3Malloc( n ); if( zStmt==0 ){ db->mallocFailed = 1; return 0; } sqlite3_snprintf(n, zStmt, "CREATE TABLE "); k = sqlite3Strlen30(zStmt); identPut(zStmt, &k, p->zName, 0); zStmt[k++] = '('; for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ sqlite3_snprintf(n-k, &zStmt[k], zSep); k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zName, 0); if( (z = pCol->zType)!=0 ){ zStmt[k++] = ' '; assert( (int)(sqlite3Strlen30(z)+k+1)<=n ); identPut(zStmt, &k, z, 1); } } sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd); return zStmt; } /* |
︙ | ︙ |
Changes to test/table.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # # $Id: table.test,v 1.50 2009/03/14 08:37:24 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic table and verify it is added to sqlite_master # do_test table-1.1 { |
︙ | ︙ | |||
394 395 396 397 398 399 400 401 402 403 404 405 406 407 | } } {1 {no such table: t5}} do_test table-8.8 { catchsql { CREATE TABLE t5 AS SELECT * FROM no_such_table; } } {1 {no such table: no_such_table}} # Make sure we cannot have duplicate column names within a table. # do_test table-9.1 { catchsql { CREATE TABLE t6(a,b,a); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } } {1 {no such table: t5}} do_test table-8.8 { catchsql { CREATE TABLE t5 AS SELECT * FROM no_such_table; } } {1 {no such table: no_such_table}} do_test table-8.9 { execsql { CREATE TABLE t10("col.1" [char.3]); CREATE TABLE t11 AS SELECT * FROM t10; SELECT sql FROM sqlite_master WHERE name = 't11'; } } {{CREATE TABLE t11("col.1" "char.3")}} do_test table-8.10 { execsql { CREATE TABLE t12( a INTEGER, b VARCHAR(10), c VARCHAR(1,10), d VARCHAR(+1,-10), e VARCHAR (+1,-10), f "VARCHAR (+1,-10, 5)", g BIG INTEGER ); CREATE TABLE t13 AS SELECT * FROM t12; SELECT sql FROM sqlite_master WHERE name = 't13'; } } {{CREATE TABLE t13( a INTEGER, b VARCHAR(10), c VARCHAR(1,10), d VARCHAR(+1,-10), e VARCHAR (+1,-10), f "VARCHAR (+1,-10, 5)", g "BIG INTEGER" )}} # Make sure we cannot have duplicate column names within a table. # do_test table-9.1 { catchsql { CREATE TABLE t6(a,b,a); } |
︙ | ︙ |