private string GetLoadingSelectStatement(ClassInfo classInfo, TableInfo tableInfo, out TableInfo[] loadedTables)
        {
            TableLoadingCache cache;

            if (tableLoadingCache.TryGetValue(tableInfo, out cache))
            {
                loadedTables = cache.LoadedTables;
                return(cache.SelectStatement);
            }

            Queue <_QueueItem> queue      = new Queue <_QueueItem>();
            List <TableInfo>   additional = new List <TableInfo>();

            additional.Add(tableInfo);

            SoqlQueryExpression queryExpression = new SoqlQueryExpression();

            queryExpression.From.Add(classInfo.Name);
            queryExpression.FromAliases.Add("");

            foreach (FieldInfo fi in tableInfo.Fields)
            {
                SoqlPathExpression pathExpr = new SoqlPathExpression(fi.Name);
                queryExpression.SelectExpressions.Add(pathExpr);
                queryExpression.SelectAliases.Add("");

                if (fi.ReferencedClass != null && fi.PrefetchLevel > 0)
                {
                    _QueueItem item = new _QueueItem();
                    item.classInfo = fi.ReferencedClass;
                    item.level     = fi.PrefetchLevel;
                    item.prefix    = pathExpr;
                    queue.Enqueue(item);
                }
            }

            // TODO - add prefetching
            while (queue.Count > 0)
            {
                _QueueItem it = queue.Dequeue();

                foreach (TableInfo ti in it.classInfo.UnifiedTables)
                {
                    additional.Add(ti);

                    foreach (FieldInfo fi in ti.Fields)
                    {
                        // TODO - this relies on the fact that path expressions
                        // are never reconstructed or broken. We simply share previous prefix
                        // perhaps it's cleaner to Clone() the expression here

                        SoqlPathExpression extendedExpression = new SoqlPathExpression(it.prefix, fi.Name);

                        queryExpression.SelectExpressions.Add(extendedExpression);
                        queryExpression.SelectAliases.Add("");

                        if (it.level >= 1 && fi.PrefetchLevel > 0 && fi.ReferencedClass != null)
                        {
                            _QueueItem newItem = new _QueueItem();
                            newItem.classInfo = fi.ReferencedClass;
                            newItem.prefix    = extendedExpression;
                            newItem.level     = it.level - 1;
                            queue.Enqueue(newItem);
                        }
                    }
                }
            }

            queryExpression.WhereClause = null;

            int parameterPos = 0;

            foreach (FieldInfo fi in tableInfo.Fields)
            {
                if (fi.IsPrimaryKey)
                {
                    SoqlBooleanRelationalExpression expr = Soql.FieldEqualsParam(fi.Name, parameterPos);

                    if (parameterPos == 0)
                    {
                        queryExpression.WhereClause = expr;
                    }
                    else
                    {
                        queryExpression.WhereClause = new SoqlBooleanAndExpression(queryExpression.WhereClause, expr);
                    }
                    parameterPos++;
                }
            }

            string query = SoqlToSql(queryExpression, tableInfo.OwnerClass.Schema, false);

            // logger.Debug("Loading statement for table {0}: {1}", tableInfo.NameToken, query);

            loadedTables = additional.ToArray();
            tableLoadingCache[tableInfo] = new TableLoadingCache(query, loadedTables);
            return(query);
        }
        private string GetLoadingSelectStatement(ClassInfo classInfo, TableInfo tableInfo, out TableInfo[] loadedTables)
        {
            TableLoadingCache cache;
            if (tableLoadingCache.TryGetValue(tableInfo, out cache))
            {
                loadedTables = cache.LoadedTables;
                return cache.SelectStatement;
            }

            Queue<_QueueItem> queue = new Queue<_QueueItem>();
            List<TableInfo> additional = new List<TableInfo>();
            additional.Add(tableInfo);

            SoqlQueryExpression queryExpression = new SoqlQueryExpression();
            queryExpression.From.Add(classInfo.Name);
            queryExpression.FromAliases.Add("");

            foreach (FieldInfo fi in tableInfo.Fields)
            {
                SoqlPathExpression pathExpr = new SoqlPathExpression(fi.Name);
                queryExpression.SelectExpressions.Add(pathExpr);
                queryExpression.SelectAliases.Add("");

                if (fi.ReferencedClass != null && fi.PrefetchLevel > 0)
                {
                    _QueueItem item = new _QueueItem();
                    item.classInfo = fi.ReferencedClass;
                    item.level = fi.PrefetchLevel;
                    item.prefix = pathExpr;
                    queue.Enqueue(item);
                }
            }

            // TODO - add prefetching
            while (queue.Count > 0)
            {
                _QueueItem it = queue.Dequeue();

                foreach (TableInfo ti in it.classInfo.UnifiedTables)
                {
                    additional.Add(ti);

                    foreach (FieldInfo fi in ti.Fields)
                    {
                        // TODO - this relies on the fact that path expressions
                        // are never reconstructed or broken. We simply share previous prefix
                        // perhaps it's cleaner to Clone() the expression here

                        SoqlPathExpression extendedExpression = new SoqlPathExpression(it.prefix, fi.Name);

                        queryExpression.SelectExpressions.Add(extendedExpression);
                        queryExpression.SelectAliases.Add("");

                        if (it.level >= 1 && fi.PrefetchLevel > 0 && fi.ReferencedClass != null)
                        {
                            _QueueItem newItem = new _QueueItem();
                            newItem.classInfo = fi.ReferencedClass;
                            newItem.prefix = extendedExpression;
                            newItem.level = it.level - 1;
                            queue.Enqueue(newItem);
                        }
                    }
                }
            }

            queryExpression.WhereClause = null;

            int parameterPos = 0;

            foreach (FieldInfo fi in tableInfo.Fields)
            {
                if (fi.IsPrimaryKey)
                {
                    SoqlBooleanRelationalExpression expr = Soql.FieldEqualsParam(fi.Name, parameterPos);

                    if (parameterPos == 0)
                    {
                        queryExpression.WhereClause = expr;
                    }
                    else
                    {
                        queryExpression.WhereClause = new SoqlBooleanAndExpression(queryExpression.WhereClause, expr);
                    }
                    parameterPos++;
                }
            }

            string query = SoqlToSql(queryExpression, tableInfo.OwnerClass.Schema, false);

            // logger.Debug("Loading statement for table {0}: {1}", tableInfo.NameToken, query);

            loadedTables = additional.ToArray();
            tableLoadingCache[tableInfo] = new TableLoadingCache(query, loadedTables);
            return query;
        }