[tarantool-patches] [PATCH 4/6] sql: don't add string of 'CREATE TABLE...' to space opts

Nikita Pettik korablev at tarantool.org
Mon Dec 10 00:30:24 MSK 2018


We don't rely no more on this string anymore and it can be removed for
ordinary tables. However, it is still used to hold SELECT body for view.

Part of #2647
---
 src/box/sql.c           |   8 +-
 src/box/sql/analyze.c   |   2 +-
 src/box/sql/build.c     | 242 ++----------------------------------------------
 src/box/sql/pragma.c    |   2 -
 src/box/sql/sqliteInt.h |   1 -
 test/sql/upgrade.result |   8 +-
 test/sql/view.result    |   3 +
 test/sql/view.test.lua  |   1 +
 8 files changed, 19 insertions(+), 248 deletions(-)

diff --git a/src/box/sql.c b/src/box/sql.c
index e9fa89df9..e79265823 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1070,7 +1070,6 @@ char *
 sql_encode_table_opts(struct region *region, struct Table *table,
 		      const char *sql, uint32_t *size)
 {
-	assert(sql != NULL);
 	size_t used = region_used(region);
 	struct mpstream stream;
 	bool is_error = false;
@@ -1087,11 +1086,12 @@ sql_encode_table_opts(struct region *region, struct Table *table,
 			a = checks->a;
 		}
 	}
-	mpstream_encode_map(&stream, 1 + is_view + (checks_cnt > 0));
+	assert(is_view || sql == NULL);
+	mpstream_encode_map(&stream, 2 * is_view + (checks_cnt > 0));
 
-	mpstream_encode_str(&stream, "sql");
-	mpstream_encode_str(&stream, sql);
 	if (is_view) {
+		mpstream_encode_str(&stream, "sql");
+		mpstream_encode_str(&stream, sql);
 		mpstream_encode_str(&stream, "view");
 		mpstream_encode_bool(&stream, true);
 	}
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index 3f492800c..8f8b6eb5d 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -1056,7 +1056,7 @@ loadAnalysis(Parse * pParse)
 static int
 sql_space_foreach_analyze(struct space *space, void *data)
 {
-	if (space->def->opts.sql == NULL || space->def->opts.is_view)
+	if (space->def->opts.is_view)
 		return 0;
 	vdbe_emit_analyze_space((struct Parse*)data, space);
 	return 0;
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 52f0bde15..fd1666c6d 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -595,102 +595,6 @@ sql_column_add_nullable_action(struct Parse *parser,
 	field->is_nullable = action_is_nullable(nullable_action);
 }
 
-/*
- * Scan the column type name zType (length nType) and return the
- * associated affinity type.
- *
- * This routine does a case-independent search of zType for the
- * substrings in the following table. If one of the substrings is
- * found, the corresponding affinity is returned. If zType contains
- * more than one of the substrings, entries toward the top of
- * the table take priority. For example, if zType is 'BLOBINT',
- * AFFINITY_INTEGER is returned.
- *
- * Substring     | Affinity
- * --------------------------------
- * 'INT'         | AFFINITY_INTEGER
- * 'CHAR'        | AFFINITY_TEXT
- * 'CLOB'        | AFFINITY_TEXT
- * 'TEXT'        | AFFINITY_TEXT
- * 'BLOB'        | AFFINITY_BLOB
- * 'REAL'        | AFFINITY_REAL
- * 'FLOA'        | AFFINITY_REAL
- * 'DOUB'        | AFFINITY_REAL
- *
- * If none of the substrings in the above table are found,
- * AFFINITY_NUMERIC is returned.
- */
-char
-sqlite3AffinityType(const char *zIn, u8 * pszEst)
-{
-	u32 h = 0;
-	char aff = AFFINITY_NUMERIC;
-	const char *zChar = 0;
-
-	assert(zIn != 0);
-	while (zIn[0]) {
-		h = (h << 8) + sqlite3UpperToLower[(*zIn) & 0xff];
-		zIn++;
-		if (h == (('c' << 24) + ('h' << 16) + ('a' << 8) + 'r')) {	/* CHAR */
-			aff = AFFINITY_TEXT;
-			zChar = zIn;
-		} else if (h == (('c' << 24) + ('l' << 16) + ('o' << 8) + 'b')) {	/* CLOB */
-			aff = AFFINITY_TEXT;
-		} else if (h == (('t' << 24) + ('e' << 16) + ('x' << 8) + 't')) {	/* TEXT */
-			aff = AFFINITY_TEXT;
-		} else if (h == (('b' << 24) + ('l' << 16) + ('o' << 8) + 'b')	/* BLOB */
-			   &&(aff == AFFINITY_NUMERIC
-			      || aff == AFFINITY_REAL)) {
-			aff = AFFINITY_BLOB;
-			if (zIn[0] == '(')
-				zChar = zIn;
-#ifndef SQLITE_OMIT_FLOATING_POINT
-		} else if (h == (('r' << 24) + ('e' << 16) + ('a' << 8) + 'l')	/* REAL */
-			   &&aff == AFFINITY_NUMERIC) {
-			aff = AFFINITY_REAL;
-		} else if (h == (('f' << 24) + ('l' << 16) + ('o' << 8) + 'a')	/* FLOA */
-			   &&aff == AFFINITY_NUMERIC) {
-			aff = AFFINITY_REAL;
-		} else if (h == (('d' << 24) + ('o' << 16) + ('u' << 8) + 'b')	/* DOUB */
-			   &&aff == AFFINITY_NUMERIC) {
-			aff = AFFINITY_REAL;
-#endif
-		} else if ((h & 0x00FFFFFF) == (('i' << 16) + ('n' << 8) + 't')) {	/* INT */
-			aff = AFFINITY_INTEGER;
-			break;
-		}
-	}
-
-	/* If pszEst is not NULL, store an estimate of the field size.  The
-	 * estimate is scaled so that the size of an integer is 1.
-	 */
-	if (pszEst) {
-		*pszEst = 1;	/* default size is approx 4 bytes
-		*/
-		if (aff < AFFINITY_NUMERIC) {
-			if (zChar) {
-				while (zChar[0]) {
-					if (sqlite3Isdigit(zChar[0])) {
-						int v = 0;
-						sqlite3GetInt32(zChar, &v);
-						v = v / 4 + 1;
-						if (v > 255)
-							v = 255;
-						*pszEst = v;	/* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1)
-						*/
-						break;
-					}
-					zChar++;
-				}
-			} else {
-				*pszEst = 5;	/* BLOB, TEXT, CLOB -> r=5  (approx 20 bytes)
-				*/
-			}
-		}
-	}
-	return aff;
-}
-
 /*
  * The expression is the default value for the most recently added column
  * of the table currently under construction.
@@ -959,136 +863,6 @@ vdbe_emit_open_cursor(struct Parse *parse_context, int cursor, int index_id,
 				 index_id, 0, (void *) space, P4_SPACEPTR);
 }
 
-/*
- * Measure the number of characters needed to output the given
- * identifier.  The number returned includes any quotes used
- * but does not include the null terminator.
- *
- * The estimate is conservative.  It might be larger that what is
- * really needed.
- */
-static int
-identLength(const char *z)
-{
-	int n;
-	for (n = 0; *z; n++, z++) {
-		if (*z == '"') {
-			n++;
-		}
-	}
-	return n + 2;
-}
-
-/*
- * 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)
-{
-	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
-	    || zIdent[j] != 0 || j == 0;
-
-	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;
-	*pIdx = i;
-}
-
-/*
- * Generate a CREATE TABLE statement appropriate for the given
- * table.  Memory to hold the text of the statement is obtained
- * from sqliteMalloc() and must be freed by the calling function.
- */
-static char *
-createTableStmt(sqlite3 * db, Table * p)
-{
-	char *zStmt;
-	char *zSep, *zSep2, *zEnd;
-	int n = 0;
-	for (uint32_t i = 0; i < p->def->field_count; i++)
-		n += identLength(p->def->fields[i].name) + 5;
-	n += identLength(p->def->name);
-	if (n < 50) {
-		zSep = "";
-		zSep2 = ",";
-		zEnd = ")";
-	} else {
-		zSep = "\n  ";
-		zSep2 = ",\n  ";
-		zEnd = "\n)";
-	}
-	n += 35 + 6 * p->def->field_count;
-	zStmt = sqlite3DbMallocRaw(0, n);
-	if (zStmt == 0) {
-		sqlite3OomFault(db);
-		return 0;
-	}
-	sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
-	int k = sqlite3Strlen30(zStmt);
-	identPut(zStmt, &k, p->def->name);
-	zStmt[k++] = '(';
-	for (uint32_t i = 0; i < p->def->field_count; i++) {
-		static const char *const azType[] = {
-			/* AFFINITY_BLOB    */ "",
-			/* AFFINITY_TEXT    */ " TEXT",
-			/* AFFINITY_NUMERIC */ " NUM",
-			/* AFFINITY_INTEGER */ " INT",
-			/* AFFINITY_REAL    */ " REAL"
-		};
-		int len;
-		const char *zType;
-
-		sqlite3_snprintf(n - k, &zStmt[k], zSep);
-		k += sqlite3Strlen30(&zStmt[k]);
-		zSep = zSep2;
-		identPut(zStmt, &k, p->def->fields[i].name);
-		char affinity = p->def->fields[i].affinity;
-		assert(affinity - AFFINITY_BLOB >= 0);
-		assert(affinity - AFFINITY_BLOB < ArraySize(azType));
-		testcase(affinity == AFFINITY_BLOB);
-		testcase(affinity == AFFINITY_TEXT);
-		testcase(affinity == AFFINITY_NUMERIC);
-		testcase(affinity == AFFINITY_INTEGER);
-		testcase(affinity == AFFINITY_REAL);
-
-		zType = azType[affinity - AFFINITY_BLOB];
-		len = sqlite3Strlen30(zType);
-		assert(affinity == AFFINITY_BLOB ||
-		       affinity == sqlite3AffinityType(zType, 0));
-		memcpy(&zStmt[k], zType, len);
-		k += len;
-		assert(k <= n);
-	}
-	sqlite3_snprintf(n - k, &zStmt[k], "%s", zEnd);
-	return zStmt;
-}
-
 /*
  * Generate code to determine the new space Id.
  * Fetch the max space id seen so far from _schema and increment it.
@@ -1524,19 +1298,15 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 	if (NEVER(v == 0))
 		return;
 
-	/* Text of the CREATE TABLE or CREATE VIEW statement. */
-	char *stmt;
-	if (pSelect) {
-		stmt = createTableStmt(db, p);
-	} else {
-		struct Token *pEnd2 = p->def->opts.is_view ?
-				      &pParse->sLastToken : pEnd;
+	/* Text of the CREATE VIEW statement. */
+	char *stmt = NULL;
+	if (p->def->opts.is_view) {
+		struct Token *pEnd2 = &pParse->sLastToken;
 		int n = pEnd2->z - pParse->sNameToken.z;
 		if (pEnd2->z[0] != ';')
 			n += pEnd2->n;
-		stmt = sqlite3MPrintf(db, "CREATE %s %.*s",
-				      p->def->opts.is_view ? "VIEW" : "TABLE",
-				      n, pParse->sNameToken.z);
+		stmt = sqlite3MPrintf(db, "CREATE VIEW %.*s", n,
+				      pParse->sNameToken.z);
 	}
 	int reg_space_id = getNewSpaceId(pParse);
 	createSpace(pParse, reg_space_id, stmt);
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 5c3501702..325c272b0 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -347,8 +347,6 @@ sql_pragma_index_info(struct Parse *parse,
 	struct space *space = space_by_name(tbl_name);
 	if (space == NULL)
 		return;
-	if (space->def->opts.sql == NULL)
-		return;
 	uint32_t iid = box_index_id_by_name(space->def->id, idx_name,
 					    strlen(idx_name));
 	if (iid == BOX_ID_NIL)
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index dbf58d967..ae6886685 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -4474,7 +4474,6 @@ char* rename_trigger(sqlite3 *, char const *, char const *, bool *);
  */
 struct coll *
 sql_get_coll_seq(Parse *parser, const char *name, uint32_t *coll_id);
-char sqlite3AffinityType(const char *, u8 *);
 void sqlite3Analyze(Parse *, Token *);
 
 /**
diff --git a/test/sql/upgrade.result b/test/sql/upgrade.result
index 5e7d85109..79c7eb245 100644
--- a/test/sql/upgrade.result
+++ b/test/sql/upgrade.result
@@ -80,13 +80,13 @@ box.sql.execute("CREATE TRIGGER t2t AFTER INSERT ON t BEGIN INSERT INTO t_out VA
 ...
 box.space._space.index['name']:get('T')
 ---
-- [513, 1, 'T', 'memtx', 1, {'sql': 'CREATE TABLE t(x INTEGER PRIMARY KEY)'}, [{'affinity': 68,
-      'type': 'integer', 'nullable_action': 'abort', 'name': 'X', 'is_nullable': false}]]
+- [513, 1, 'T', 'memtx', 1, {}, [{'affinity': 68, 'type': 'integer', 'nullable_action': 'abort',
+      'name': 'X', 'is_nullable': false}]]
 ...
 box.space._space.index['name']:get('T_OUT')
 ---
-- [514, 1, 'T_OUT', 'memtx', 1, {'sql': 'CREATE TABLE t_out(x INTEGER PRIMARY KEY)'},
-  [{'affinity': 68, 'type': 'integer', 'nullable_action': 'abort', 'name': 'X', 'is_nullable': false}]]
+- [514, 1, 'T_OUT', 'memtx', 1, {}, [{'affinity': 68, 'type': 'integer', 'nullable_action': 'abort',
+      'name': 'X', 'is_nullable': false}]]
 ...
 t1t = box.space._trigger:get('T1T')
 ---
diff --git a/test/sql/view.result b/test/sql/view.result
index b211bcb2e..3d2569524 100644
--- a/test/sql/view.result
+++ b/test/sql/view.result
@@ -49,6 +49,9 @@ t1 = box.space._space.index[2]:select('T1')[1]:totable();
 t1[6]['view'] = true;
 ---
 ...
+t1[6]['sql'] = 'SELECT * FROM t1;'
+---
+...
 box.space._space:replace(t1);
 ---
 - error: 'Can''t modify space ''T1'': can not convert a space to a view and vice versa'
diff --git a/test/sql/view.test.lua b/test/sql/view.test.lua
index a6269a1bf..239e4ce5e 100644
--- a/test/sql/view.test.lua
+++ b/test/sql/view.test.lua
@@ -23,6 +23,7 @@ box.space._space:replace(v1);
 
 t1 = box.space._space.index[2]:select('T1')[1]:totable();
 t1[6]['view'] = true;
+t1[6]['sql'] = 'SELECT * FROM t1;'
 box.space._space:replace(t1);
 
 -- View can't exist without SQL statement.
-- 
2.15.1





More information about the Tarantool-patches mailing list