diff --git a/src/deveeldb-nunit/Deveel.Data/ShowTests.cs b/src/deveeldb-nunit/Deveel.Data/ShowTests.cs index a33a1475..d00d92a6 100644 --- a/src/deveeldb-nunit/Deveel.Data/ShowTests.cs +++ b/src/deveeldb-nunit/Deveel.Data/ShowTests.cs @@ -14,19 +14,76 @@ // limitations under the License. using System; +using System.Linq; + +using Deveel.Data.Security; +using Deveel.Data.Sql; +using Deveel.Data.Sql.Cursors; +using Deveel.Data.Sql.Tables; +using Deveel.Data.Sql.Types; using NUnit.Framework; namespace Deveel.Data { [TestFixture] public sealed class ShowTests : ContextBasedTest { + protected override bool OnSetUp(string testName, IQuery query) { + var tableName = ObjectName.Parse("SYSTEM.test_table"); + var tableInfo = new TableInfo(tableName); + tableInfo.AddColumn("a", PrimitiveTypes.Integer()); + tableInfo.AddColumn("b", PrimitiveTypes.String()); + + query.Access().CreateObject(tableInfo); + query.Access().GrantOnTable(tableName, User.PublicName, Privileges.TableAll); + + return true; + } + + protected override bool OnTearDown(string testName, IQuery query) { + var tableName = ObjectName.Parse("SYSTEM.test_table"); + query.Access().RevokeAllGrantsOn(DbObjectType.Table, tableName); + query.Access().DropObject(DbObjectType.Table, tableName); + return true; + } + [Test] public void ShowSchema() { var result = Query.ShowSchema(); Assert.IsNotNull(result); - // TODO: Verify the list of schema is coherent + Row row = null; + Assert.DoesNotThrow(() => row = result.ElementAt(0)); + Assert.IsNotNull(row); + + var schemaName = row.GetValue(0).Value.ToString(); + var schemaType = row.GetValue(1).Value.ToString(); + + Assert.AreEqual("INFORMATION_SCHEMA", schemaName); + Assert.AreEqual("SYSTEM", schemaType); + } + + [Test] + public void ShowTables() { + var result = Query.ShowTables(); + + Assert.IsNotNull(result); + + // TODO: There's probably an error on the views to select + // the tables the current user has access to... so for the moment + // just be happy it doesn't throw an error: we will come back later + } + + [Test] + public void ShowProduct() { + var result = Query.ShowProduct(); + + Assert.IsNotNull(result); + + // TODO: the product information come from the variables table, + // that is not yet finalized: so the execution succeeds but + // no data are retrieved. come back later when database vars + // are implemented } } } diff --git a/src/deveeldb/Deveel.Data.Routines/InvokeArgument.cs b/src/deveeldb/Deveel.Data.Routines/InvokeArgument.cs index e7588fe2..41f8260e 100644 --- a/src/deveeldb/Deveel.Data.Routines/InvokeArgument.cs +++ b/src/deveeldb/Deveel.Data.Routines/InvokeArgument.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.Serialization; +using System.Text; using Deveel.Data.Sql.Expressions; @@ -40,5 +41,16 @@ public InvokeArgument(SqlExpression value) var preparedValue = Value.Prepare(preparer); return new InvokeArgument(Name, preparedValue); } + + public override string ToString() { + var sb = new StringBuilder(); + if (IsNamed) { + sb.AppendFormat("{0} => ", Name); + } + + sb.Append(Value); + + return sb.ToString(); + } } } diff --git a/src/deveeldb/Deveel.Data.Routines/SystemFunctions.cs b/src/deveeldb/Deveel.Data.Routines/SystemFunctions.cs index f36970d9..e6e5375d 100644 --- a/src/deveeldb/Deveel.Data.Routines/SystemFunctions.cs +++ b/src/deveeldb/Deveel.Data.Routines/SystemFunctions.cs @@ -16,8 +16,11 @@ using System; +using System.Globalization; +using System.Text; using Deveel.Data; +using Deveel.Data.Security; using Deveel.Data.Sql; using Deveel.Data.Sql.Expressions; using Deveel.Data.Sql.Objects; @@ -282,6 +285,30 @@ public static class SystemFunctions { #endregion + public static Field Concat(Field[] args) { + var cc = new StringBuilder(); + + CultureInfo locale = null; + foreach (var ob in args) { + if (ob.IsNull) + return ob; + + cc.Append(ob.Value); + + var type1 = ob.Type; + if (locale == null && type1 is StringType) { + var strType = (StringType)type1; + locale = strType.Locale; + } + } + + // We inherit the locale from the first string parameter with a locale, + // or use a default VarString if no locale found. + var type = locale != null ? PrimitiveTypes.VarChar(locale) : PrimitiveTypes.VarChar(); + + return new Field(type, new SqlString(cc.ToString())); + } + internal static InvokeResult Iif(InvokeContext context) { var result = Field.Null(); @@ -343,5 +370,11 @@ public static class SystemFunctions { throw new InvalidOperationException("Unsupported type in function argument"); } + + internal static Field PrivilegeString(Field ob) { + int privBit = ((SqlNumber)ob.Value).ToInt32(); + var privs = (Privileges)privBit; + return Field.String(privs.ToString()); + } } } \ No newline at end of file diff --git a/src/deveeldb/Deveel.Data.Routines/SystemFunctionsProvider.cs b/src/deveeldb/Deveel.Data.Routines/SystemFunctionsProvider.cs index d8e9ac6e..2c2d4765 100644 --- a/src/deveeldb/Deveel.Data.Routines/SystemFunctionsProvider.cs +++ b/src/deveeldb/Deveel.Data.Routines/SystemFunctionsProvider.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using Deveel.Data; using Deveel.Data.Sql; @@ -50,6 +51,20 @@ class SystemFunctionsProvider : FunctionProvider { return exp.ReturnType(context.Request, context.VariableResolver); } + private static SqlType ConcatReturnType(InvokeContext context) { + // Determine the locale of the first string parameter. + CultureInfo locale = null; + for (int i = 0; i < context.ArgumentCount && locale == null; ++i) { + var type = ReturnType(context.Arguments[i].Value, context); + if (type is StringType) { + StringType strType = (StringType)type; + locale = strType.Locale; + } + } + + return locale != null ? PrimitiveTypes.VarChar(locale) : PrimitiveTypes.VarChar(); + } + #endregion #region Aggregate Functions @@ -60,7 +75,9 @@ class SystemFunctionsProvider : FunctionProvider { .Named("aggor") .WithParameter(p => p.Named("args").Unbounded().OfDynamicType()) .OfAggregateType() - .WhenExecute(context => Binary(context, SystemFunctions.Or))); + .WhenExecute(context => { + return Binary(context, SystemFunctions.Or); + })); // COUNT Register(config => config.Named("count") @@ -451,6 +468,11 @@ class DistinctComparer : IComparer { return argType is StringType ? (SqlType) PrimitiveTypes.Numeric() : (SqlType) PrimitiveTypes.String(); })); + Register(config => config.Named("i_privilege_string") + .WithNumericParameter("privBit") + .WhenExecute(context => Simple(context, args => SystemFunctions.PrivilegeString(args[0]))) + .ReturnsString()); + // VERSION Register(config => config .Named("version") @@ -544,6 +566,18 @@ class DistinctComparer : IComparer { #endregion + #region String Functions + + private void StringFunctions() { + // CONCAT([STRING]) + Register(config => config.Named("concat") + .WithUnoundedParameter("strings", PrimitiveTypes.VarChar()) + .WhenExecute(context => Simple(context, args => SystemFunctions.Concat(args))) + .ReturnsType(ConcatReturnType)); + } + + #endregion + protected override void OnInit() { AggregateFunctions(); @@ -551,6 +585,7 @@ class DistinctComparer : IComparer { SecurityFunctions(); SequenceFunctions(); DateFunctions(); + StringFunctions(); MiscFunctions(); } diff --git a/src/deveeldb/Deveel.Data.Sql.Cursors/NativeCursor.cs b/src/deveeldb/Deveel.Data.Sql.Cursors/NativeCursor.cs index 1190a72e..6cc49b44 100644 --- a/src/deveeldb/Deveel.Data.Sql.Cursors/NativeCursor.cs +++ b/src/deveeldb/Deveel.Data.Sql.Cursors/NativeCursor.cs @@ -129,6 +129,9 @@ class NativeCursor : ICursor { public CursorStatus Status { get; private set; } public Row Fetch(FetchDirection direction, int offset) { + if (Result == null) + return null; + if (direction != FetchDirection.Absolute && direction != FetchDirection.Relative && offset > -1) diff --git a/src/deveeldb/Deveel.Data.Sql.Expressions/PreparerVisitor.cs b/src/deveeldb/Deveel.Data.Sql.Expressions/PreparerVisitor.cs index 92c062c0..08a04248 100644 --- a/src/deveeldb/Deveel.Data.Sql.Expressions/PreparerVisitor.cs +++ b/src/deveeldb/Deveel.Data.Sql.Expressions/PreparerVisitor.cs @@ -87,7 +87,22 @@ private static IEnumerable Prepare(IEnumerable list, IExpressionPrepare if (nextComposite != null) nextComposite = (SqlQueryExpression) nextComposite.Prepare(preparer); + var groupBy = query.GroupBy; + if (groupBy != null) { + var newGroupBy = new List(); + foreach (var groupExpression in groupBy) { + var newGroupByExp = groupExpression.Prepare(preparer); + newGroupBy.Add(newGroupByExp); + } + + newExpression.GroupBy = newGroupBy; + } + newExpression.NextComposite = nextComposite; + newExpression.CompositeFunction = query.CompositeFunction; + newExpression.IsCompositeAll = query.IsCompositeAll; + + newExpression.Distinct = query.Distinct; return newExpression; } diff --git a/src/deveeldb/Deveel.Data.Sql.Query/SubsetNode.cs b/src/deveeldb/Deveel.Data.Sql.Query/SubsetNode.cs index 000d04c1..2731978c 100644 --- a/src/deveeldb/Deveel.Data.Sql.Query/SubsetNode.cs +++ b/src/deveeldb/Deveel.Data.Sql.Query/SubsetNode.cs @@ -46,12 +46,14 @@ private SubsetNode(SerializationInfo info, StreamingContext context) } public void SetAliasParentName(ObjectName parentName) { - var aliases = new ObjectName[AliasColumnNames.Length]; - for (int i = 0; i < aliases.Length; i++) { - aliases[i] = new ObjectName(parentName, AliasColumnNames[i].Name); - } + if (parentName != null) { + var aliases = new ObjectName[AliasColumnNames.Length]; + for (int i = 0; i < aliases.Length; i++) { + aliases[i] = new ObjectName(parentName, AliasColumnNames[i].Name); + } - AliasColumnNames = aliases; + AliasColumnNames = aliases; + } } protected override void GetData(SerializationInfo info, StreamingContext context) { diff --git a/src/deveeldb/Deveel.Data.Sql.Schemas/InfortmationSchemaCreate.cs b/src/deveeldb/Deveel.Data.Sql.Schemas/InfortmationSchemaCreate.cs index 4b6294ec..831fdca9 100644 --- a/src/deveeldb/Deveel.Data.Sql.Schemas/InfortmationSchemaCreate.cs +++ b/src/deveeldb/Deveel.Data.Sql.Schemas/InfortmationSchemaCreate.cs @@ -28,14 +28,14 @@ class InfortmationSchemaCreate : IDatabaseCreateCallback { " SELECT \"priv_bit\", \"object\", \"name\", \"grantee\", " + " \"grant_option\", \"granter\" " + " FROM " + SystemSchema.GrantsTableName + - " WHERE ( grantee = user() OR grantee = '@PUBLIC' )"); + " WHERE ( grantee = user() OR grantee = '" + User.PublicName + "' )"); // This view shows the grants that the user is allowed to see query.ExecuteQuery("CREATE VIEW " + InformationSchema.ThisUserGrantViewName + " AS " + " SELECT \"description\", \"object\", \"name\", \"grantee\", " + " \"grant_option\", \"granter\" " + " FROM " + SystemSchema.GrantsTableName + ", " + SystemSchema.PrivilegesTableName + - " WHERE ( grantee = user() OR grantee = '@PUBLIC' )" + + " WHERE ( grantee = user() OR grantee = '" + User.PublicName + "' )" + " AND " + SystemSchema.GrantsTableName + ".priv_bit = " + SystemSchema.PrivilegesTableName + ".priv_bit"); @@ -112,9 +112,9 @@ class InfortmationSchemaCreate : IDatabaseCreateCallback { " \"TABLE_SCHEMA\",\n" + " \"TABLE_NAME\",\n" + " \"COLUMN_NAME\",\n" + - " IIF(\"" + InformationSchema.ThisUserGrantViewName + ".granter\" = '@SYSTEM', \n" + + " IIF(\"" + InformationSchema.ThisUserGrantViewName + ".granter\" = '" + User.SystemName + "', \n" + " NULL, \"ThisUserGrant.granter\") AS \"GRANTOR\",\n" + - " IIF(\"" + InformationSchema.ThisUserGrantViewName + ".grantee\" = '@PUBLIC', \n" + + " IIF(\"" + InformationSchema.ThisUserGrantViewName + ".grantee\" = '" + User.PublicName +"', \n" + " 'public', \"ThisUserGrant.grantee\") AS \"GRANTEE\",\n" + " \"" + InformationSchema.ThisUserGrantViewName + ".description\" AS \"PRIVILEGE\",\n" + " IIF(\"grant_option\" = 'true', 'YES', 'NO') AS \"IS_GRANTABLE\" \n" + @@ -128,9 +128,9 @@ class InfortmationSchemaCreate : IDatabaseCreateCallback { " SELECT \"TABLE_CATALOG\",\n" + " \"TABLE_SCHEMA\",\n" + " \"TABLE_NAME\",\n" + - " IIF(\"" + InformationSchema.ThisUserGrantViewName + ".granter\" = '@SYSTEM', \n" + + " IIF(\"" + InformationSchema.ThisUserGrantViewName + ".granter\" = '" + User.SystemName + "', \n" + " NULL, \"ThisUserGrant.granter\") AS \"GRANTOR\",\n" + - " IIF(\"" + InformationSchema.ThisUserGrantViewName + ".grantee\" = '@PUBLIC', \n" + + " IIF(\"" + InformationSchema.ThisUserGrantViewName + ".grantee\" = '" + User.PublicName + "', \n" + " 'public', \"ThisUserGrant.grantee\") AS \"GRANTEE\",\n" + " \"" + InformationSchema.ThisUserGrantViewName + ".description\" AS \"PRIVILEGE\",\n" + " IIF(\"grant_option\" = 'true', 'YES', 'NO') AS \"IS_GRANTABLE\" \n" + diff --git a/src/deveeldb/Deveel.Data.Sql.Statements/SelectStatement.cs b/src/deveeldb/Deveel.Data.Sql.Statements/SelectStatement.cs index 2ebdf784..2c12b58d 100644 --- a/src/deveeldb/Deveel.Data.Sql.Statements/SelectStatement.cs +++ b/src/deveeldb/Deveel.Data.Sql.Statements/SelectStatement.cs @@ -78,6 +78,24 @@ private SelectStatement(SerializationInfo info, StreamingContext context) } } + protected override SqlStatement PrepareExpressions(IExpressionPreparer preparer) { + var preparedQuery = QueryExpression.Prepare(preparer); + if (!(preparedQuery is SqlQueryExpression)) + throw new StatementException("The preparation of the query expression resulted in an invalid expression."); + + var orderBy = new List(); + if (OrderBy != null) { + foreach (var column in OrderBy) { + var prepared = (SortColumn) ((IPreparable) column).Prepare(preparer); + orderBy.Add(prepared); + } + } + + var query = (SqlQueryExpression) preparedQuery; + + return new SelectStatement(query, Limit, orderBy); + } + protected override SqlStatement PrepareStatement(IRequest context) { var queryPlan = context.Query.Context.QueryPlanner().PlanQuery(new QueryInfo(context, QueryExpression, OrderBy, Limit)); return new Prepared(queryPlan); diff --git a/src/deveeldb/Deveel.Data.Sql.Statements/ShowStatement.cs b/src/deveeldb/Deveel.Data.Sql.Statements/ShowStatement.cs index f6a1f3c1..282c2ead 100644 --- a/src/deveeldb/Deveel.Data.Sql.Statements/ShowStatement.cs +++ b/src/deveeldb/Deveel.Data.Sql.Statements/ShowStatement.cs @@ -16,10 +16,13 @@ using System; +using System.Runtime.Serialization; using Deveel.Data.Sql.Expressions; +using Deveel.Data.Sql.Objects; using Deveel.Data.Sql.Schemas; using Deveel.Data.Sql.Tables; +using Deveel.Data.Sql.Types; namespace Deveel.Data.Sql.Statements { [Serializable] @@ -47,57 +50,118 @@ public ShowStatement(ShowTarget target) } if (Target == ShowTarget.Schema) - return ShowSchema(context.Context); + return ShowSchema(); if (Target == ShowTarget.SchemaTables) - return ShowSchemaTables(context.Query.CurrentSchema(), context.Context); + return ShowSchemaTables(context.Query.CurrentSchema()); + if (Target == ShowTarget.Table) + return ShowTable(tableName); + if (Target == ShowTarget.Product) + return ShowProduct(); throw new StatementException(String.Format("The SHOW target {0} is not supported.", Target)); } - private static SqlStatement Show(IContext context, string sql, params SortColumn[] orderBy) { - var query = (SqlQueryExpression)SqlExpression.Parse(sql, context); - var select = new SelectStatement(query, orderBy); - return new Prepared(select); + private static SqlStatement Show(string sql, params QueryParameter[] parameters) { + var query = new SqlQuery(sql); + if (parameters != null && parameters.Length > 0) { + foreach (var parameter in parameters) { + query.Parameters.Add(parameter); + } + } + + return new Prepared(query); } - private SqlStatement ShowSchema(IContext systemContext) { + private SqlStatement ShowSchema() { var sql = "SELECT \"name\" AS \"schema_name\", " + " \"type\", " + " \"other\" AS \"notes\" " + - " FROM " + InformationSchema.ThisUserSchemaInfoViewName; + " FROM " + InformationSchema.ThisUserSchemaInfoViewName + " " + + "ORDER BY \"schema_name\""; - return Show(systemContext, sql, new SortColumn("schema_name")); + return Show(sql); } - private SqlStatement ShowSchemaTables(string schema, IContext context) { + private SqlStatement ShowProduct() { + const string sql = "SELECT \"name\", \"version\" FROM " + + " ( SELECT \"value\" AS \"name\" FROM SYSTEM.product_info " + + " WHERE \"var\" = 'name' ), " + + " ( SELECT \"value\" AS \"version\" FROM SYSTEM.product_info " + + " WHERE \"var\" = 'version' ) "; + + return Show(sql); + } + + private SqlStatement ShowSchemaTables(string schema) { var sql = " SELECT \"Tables.TABLE_NAME\" AS \"table_name\", " + " I_PRIVILEGE_STRING(\"agg_priv_bit\") AS \"user_privs\", " + " \"Tables.TABLE_TYPE\" as \"table_type\" " + " FROM " + InformationSchema.Tables + ", " + " ( SELECT AGGOR(\"priv_bit\") agg_priv_bit, " + - " \"object\", \"param\" " + + " \"object\", \"name\" " + " FROM " + InformationSchema.ThisUserSimpleGrantViewName + - " WHERE \"object\" = 1 " + - " GROUP BY \"param\" )" + - " WHERE \"Tables.TABLE_SCHEMA\" = \"" + schema + "\" " + - " AND CONCAT(\"Tables.TABLE_SCHEMA\", '.', \"Tables.TABLE_NAME\") = \"param\" "; - return Show(context, sql, new SortColumn("Tables.TABLE_NAME")); + " WHERE \"object\" = " + ((int)DbObjectType.Table) + + " GROUP BY \"name\" )" + + " WHERE \"Tables.TABLE_SCHEMA\" = ? " + + " AND CONCAT(\"Tables.TABLE_SCHEMA\", '.', \"Tables.TABLE_NAME\") = \"name\" " + + "ORDER BY Tables.TABLE_NAME"; + + var param = new QueryParameter(PrimitiveTypes.String(), new SqlString(schema)); + return Show(sql, param); + } + + private SqlStatement ShowTable(ObjectName tableName) { + var sql = " SELECT \"column\" AS \"name\", " + + " i_sql_type(\"type_desc\", \"size\", \"scale\") AS \"type\", " + + " \"not_null\", " + + " \"index_str\" AS \"index\", " + + " \"default\" " + + " FROM " + InformationSchema.ThisUserTableColumnsViewName + " " + + " WHERE \"schema\" = ? " + + " AND \"table\" = ? " + + "ORDER BY \"seq_no\" "; + + var parameters = new[] { + new QueryParameter(PrimitiveTypes.String(), new SqlString(tableName.ParentName)), + new QueryParameter(PrimitiveTypes.String(), new SqlString(tableName.Name)) + }; + + return Show(sql, parameters); } #region Prepared + [Serializable] class Prepared : SqlStatement { - public Prepared(SelectStatement select) { - Select = select; + public Prepared(SqlQuery query) { + Query = query; } - public SelectStatement Select { get; private set; } + private Prepared(SerializationInfo info, StreamingContext context) + : base(info, context) { + Query = (SqlQuery) info.GetValue("Query", typeof(SqlQuery)); + } + + public SqlQuery Query { get; private set; } + + protected override void GetData(SerializationInfo info) { + info.AddValue("Query", Query); + base.GetData(info); + } protected override void ExecuteStatement(ExecutionContext context) { - var result = context.Request.ExecuteStatement(Select); + var results = context.Query.ExecuteQuery(Query); + + if (results.Length != 1) + throw new StatementException("Too many queries were executed."); + + var result = results[0]; + + if (result.Type == StatementResultType.Exception) + throw result.Error; if (result.Type != StatementResultType.CursorRef) - throw new StatementException(); + throw new StatementException("Invalid result for query"); context.SetCursor(result.Cursor); } diff --git a/src/deveeldb/Deveel.Data.Sql.Tables/FilterTable.cs b/src/deveeldb/Deveel.Data.Sql.Tables/FilterTable.cs index 6220fefe..15237737 100644 --- a/src/deveeldb/Deveel.Data.Sql.Tables/FilterTable.cs +++ b/src/deveeldb/Deveel.Data.Sql.Tables/FilterTable.cs @@ -74,6 +74,7 @@ class FilterTable : Table { // Index is not cached in this table so ask the parent. index = Parent.GetIndex(column, originalColumn, t); + if (table == this) columnIndices[column] = index; diff --git a/src/deveeldb/Deveel.Data.Sql.Tables/FunctionTable.cs b/src/deveeldb/Deveel.Data.Sql.Tables/FunctionTable.cs index 9449787d..34b04373 100644 --- a/src/deveeldb/Deveel.Data.Sql.Tables/FunctionTable.cs +++ b/src/deveeldb/Deveel.Data.Sql.Tables/FunctionTable.cs @@ -124,7 +124,7 @@ public FunctionTable(ITable table, SqlExpression[] functionList, string[] column public override void Lock() { // We Lock the reference table. // NOTE: This cause the reference table to Lock twice when we use the - // 'MergeWithReference' method. While this isn't perfect behaviour, it + // 'MergeWith' method. While this isn't perfect behaviour, it // means if 'MergeWithReference' isn't used, we still maintain a safe // level of locking. ReferenceTable.Lock(); @@ -133,7 +133,7 @@ public FunctionTable(ITable table, SqlExpression[] functionList, string[] column public override void Release() { // We unlock the reference table. // NOTE: This cause the reference table to unlock twice when we use the - // 'MergeWithReference' method. While this isn't perfect behaviour, it + // 'MergeWith' method. While this isn't perfect behaviour, it // means if 'MergeWithReference' isn't used, we still maintain a safe // level of locking. ReferenceTable.Release(); @@ -271,7 +271,7 @@ public FunctionTable(ITable table, SqlExpression[] functionList, string[] column rowList.Add(rowEnum.Current.RowId.RowNumber); } else { // MAJOR HACK: If the referencing table has no elements then we choose - // an arbitary index from the reference table to merge so we have + // an arbitrary index from the reference table to merge so we have // at least one element in the table. // This is to fix the 'SELECT COUNT(*) FROM empty_table' bug. rowList.Add(Int32.MaxValue - 1); diff --git a/src/deveeldb/Deveel.Data.Sql.Tables/OuterTable.cs b/src/deveeldb/Deveel.Data.Sql.Tables/OuterTable.cs index f9f76fa8..f6b9ec41 100644 --- a/src/deveeldb/Deveel.Data.Sql.Tables/OuterTable.cs +++ b/src/deveeldb/Deveel.Data.Sql.Tables/OuterTable.cs @@ -21,7 +21,7 @@ using Deveel.Data.Index; namespace Deveel.Data.Sql.Tables { - internal class OuterTable : VirtualTable { + internal class OuterTable : VirtualTable, IRootTable { private readonly IList[] outerRows; private int outerRowCount; @@ -42,6 +42,10 @@ private OuterTable(IEnumerable tables, IList> rows) get { return base.RowCount + outerRowCount; } } + bool IRootTable.TypeEquals(IRootTable other) { + return this == other; + } + public void MergeIn(ITable outsideTable) { var rawTableInfo = outsideTable.GetRawTableInfo(); diff --git a/src/deveeldb/Deveel.Data.Sql.Tables/VirtualTable.cs b/src/deveeldb/Deveel.Data.Sql.Tables/VirtualTable.cs index 91248150..f849b34e 100644 --- a/src/deveeldb/Deveel.Data.Sql.Tables/VirtualTable.cs +++ b/src/deveeldb/Deveel.Data.Sql.Tables/VirtualTable.cs @@ -73,11 +73,20 @@ public VirtualTable(ITable table, IList rows) } protected override IEnumerable ResolveRowsForTable(IEnumerable rows, int tableNum) { - var rowSet = rows.ToList(); + var rowSet = new List(rows); IList curRowList = rowList[tableNum]; for (int n = rowSet.Count - 1; n >= 0; --n) { int aa = rowSet[n]; - int bb = curRowList[aa]; + int bb; + + if (aa == Int32.MaxValue - 1) { + bb = 0; + } else if (aa < 0 || aa >= curRowList.Count) { + throw new InvalidOperationException("Invalid row reference"); + } else { + bb = curRowList[aa]; + } + rowSet[n] = bb; } diff --git a/src/deveeldb/Deveel.Data/RequestExtensions.cs b/src/deveeldb/Deveel.Data/RequestExtensions.cs index d2c74c0d..61360cfa 100644 --- a/src/deveeldb/Deveel.Data/RequestExtensions.cs +++ b/src/deveeldb/Deveel.Data/RequestExtensions.cs @@ -503,6 +503,10 @@ public static class RequestExtensions { return request.Show(ShowTarget.SchemaTables); } + public static ICursor ShowTable(this IRequest request, ObjectName tableName) { + return request.Show(ShowTarget.Table, tableName); + } + public static ICursor ShowStatus(this IRequest request) { return request.Show(ShowTarget.Status); } @@ -511,6 +515,10 @@ public static class RequestExtensions { return request.Show(ShowTarget.Session); } + public static ICursor ShowProduct(this IRequest request) { + return request.Show(ShowTarget.Product); + } + #endregion #endregion