From f763386c614b5308ee050b9d6a0939878fa648bc Mon Sep 17 00:00:00 2001
From: Ivan Koptelov <ivan.koptelov@tarantool.org>
Date: Fri, 25 May 2018 19:11:35 +0300
Subject: [PATCH] add index_def to Index

github branch: https://github.com/tarantool/tarantool/tree/sb/gh-3369-use-index-def-in-select-and-where
---
 src/box/sql/build.c     | 156 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/box/sql/sqliteInt.h |   1 +
 2 files changed, 157 insertions(+)

diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index e3762959e..09e059858 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -251,6 +251,8 @@ sqlite3LocateIndex(sqlite3 * db, const char *zName, const char *zTable)
 static void
 freeIndex(sqlite3 * db, Index * p)
 {
+	if (p->def != NULL)
+		index_def_delete(p->def);
 	sql_expr_free(db, p->pPartIdxWhere, false);
 	sqlite3ExprListDelete(db, p->aColExpr);
 	sqlite3DbFree(db, p->zColAff);
@@ -2820,6 +2822,151 @@ index_is_unique(Index *idx)
 	return tnt_index->def->opts.is_unique;
 }
 
+uint32_t
+get_new_iid(Index *indexes)
+{
+	uint32_t max_iid = 0;
+	Index *idx;
+
+	if (indexes == NULL)
+		return 0;
+
+	for (idx = indexes; idx; idx = idx->pNext)
+		max_iid = idx->def->iid > max_iid ? idx->def->iid : max_iid;
+
+	return max_iid + 1;
+}
+
+void
+append(struct region *r, const char *str, char **sql_arr, int idx, int total_sql_str_size)
+{
+	sql_arr[idx] = region_alloc(r, strlen(str));
+	strcpy(sql_arr[idx], str);
+	total_sql_str_size += strlen(str);
+}
+
+char *
+create_sql(const char *idx_name, struct space_def *space_def, ExprList *expr_list)
+{
+	struct region *r = &fiber()->gc;
+	/*
+	 * CREATE_INDEX_ + INDEX_NAME + _ON_ + TABLE_NAME + _(
+	 */
+	uint32_t sql_parts_count = 5;
+	Expr *column_expr;
+	for (uint32_t i = 0; i < (uint32_t) expr_list->nExpr; i++){
+		column_expr = sqlite3ExprSkipCollate(expr_list->a[i].pExpr);
+		sql_parts_count += expr_list->a[i].pExpr == column_expr ? 2 : 4;
+	}
+
+	size_t total_sql_str_size = 0;
+
+	char **sql = region_alloc(r, sizeof(char*) * sql_parts_count);
+
+	char *CREATE_INDEX = "CREATE INDEX ";
+	append(r, CREATE_INDEX, sql, 0, total_sql_str_size);
+	append(r, idx_name, sql, 1, total_sql_str_size);
+
+	char *ON = " ON ";
+	append(r, ON, sql, 2, total_sql_str_size);
+
+	char *name = space_def->name;
+	append(r, name, sql, 3, total_sql_str_size);
+	append(r, " (", sql, 4, total_sql_str_size);
+
+	Expr *collation_expr;
+	uint32_t sql_idx = 5;
+	for (int i = 0; i < expr_list->nExpr; i++){
+		column_expr = sqlite3ExprSkipCollate(expr_list->a[i].pExpr);
+		collation_expr = expr_list->a[i].pExpr == column_expr ?
+				 NULL : expr_list->a[i].pExpr;
+
+		name = space_def->fields[column_expr->iColumn].name;
+
+		if (collation_expr == NULL){
+			append(r, name, sql, sql_idx, total_sql_str_size);
+			sql_idx++;
+
+			append(r, ", ", sql, sql_idx, total_sql_str_size);
+			sql_idx++;
+
+		} else {
+			append(r, name, sql, sql_idx, total_sql_str_size);
+			sql_idx++;
+
+			char *COLLATE = " COLLATE ";
+			append(r, COLLATE, sql, sql_idx, total_sql_str_size);
+			sql_idx++;
+
+			char *coll_name = collation_expr->u.zToken;
+			append(r, coll_name, sql, sql_idx, total_sql_str_size);
+			sql_idx++;
+
+			append(r, ", ", sql, sql_idx, total_sql_str_size);
+			sql_idx++;
+		}
+	}
+
+	// fix last ", " with ")\0"
+	strcpy(sql[sql_idx - 1], ")\0");
+	char *res = region_join(r, total_sql_str_size);
+	return res;
+}
+
+void
+set_index_def(Parse *parse, Index *index, Table *table,
+				   const char *name,
+				   uint32_t name_len, int on_error,
+				   ExprList *expr_list, u8 idx_type)
+{
+	struct space_def *space_def = table->def;
+
+	uint32_t iid = get_new_iid(table->pIndex);
+	struct index_opts opts;
+	index_opts_create(&opts);
+	opts.stat = NULL;
+	opts.is_unique = on_error != ON_CONFLICT_ACTION_NONE;
+
+	struct key_def *key_def = key_def_new(expr_list->nExpr);
+
+	if (idx_type == SQLITE_IDXTYPE_APPDEF) {
+		opts.sql = create_sql(name, table->def, expr_list);
+	}
+
+	int i = 0;
+	Expr *column_expr;
+	Expr *collation_expr;
+	for (i = 0; i < expr_list->nExpr; i++) {
+		column_expr = sqlite3ExprSkipCollate(expr_list->a[i].pExpr);
+		collation_expr = expr_list->a[i].pExpr == column_expr ?
+				 NULL : expr_list->a[i].pExpr;
+
+		uint32_t fieldno = column_expr->iColumn;
+
+		uint32_t coll_id;
+		struct coll *coll;
+		if (collation_expr != NULL)
+			coll = sql_get_coll_seq(parse, collation_expr->u.zToken,&coll_id);
+		else
+			coll = sql_column_collation(space_def, fieldno, &coll_id);
+
+		key_def_set_part(key_def, i, fieldno,
+				space_def->fields[fieldno].type,
+				space_def->fields[fieldno].nullable_action,
+				coll, coll_id, SORT_ORDER_ASC);
+	}
+
+	struct key_def *pk_key_def;
+	if (idx_type == SQLITE_IDXTYPE_APPDEF) {
+		pk_key_def = table->pIndex->def->key_def;
+	} else {
+		pk_key_def = NULL;
+	}
+
+	index->def = index_def_new(space_def->id, iid, name, name_len,
+			     TREE, &opts, key_def, pk_key_def);
+}
+
 void
 sql_create_index(struct Parse *parse, struct Token *token,
 		 struct SrcList *tbl_name, struct ExprList *col_list,
@@ -3133,6 +3280,10 @@ sql_create_index(struct Parse *parse, struct Token *token,
 				}
 				if (idx_type == SQLITE_IDXTYPE_PRIMARYKEY)
 					pIdx->idxType = idx_type;
+
+				set_index_def(parse, pIndex, pTab, zName,
+					      nName, on_error, col_list,
+					      idx_type);
 				goto exit_create_index;
 			}
 		}
@@ -3141,6 +3292,11 @@ sql_create_index(struct Parse *parse, struct Token *token,
 	/* Link the new Index structure to its table and to the other
 	 * in-memory database structures.
 	 */
+
+	set_index_def(parse, pIndex, pTab, zName,
+		      nName, on_error, col_list,
+		      idx_type);
+
 	assert(parse->nErr == 0);
 	if (db->init.busy) {
 		Index *p;
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 950409d93..fe61dacfe 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -2124,6 +2124,7 @@ struct Index {
 				 * or _NONE
 				 */
 	unsigned idxType:2;	/* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
+    	struct index_def *def;
 };
 
 /**
-- 
2.14.3 (Apple Git-98)

