private StatementList GetIndexArray(Hashtable from, Resource entity) {
			StatementList ret = (StatementList)from[entity];
			if (ret == null) {
				ret = new StatementList();
				from[entity] = ret;
			}
			return ret;
		}
		private void RunAddBuffer() {
			if (addStatementBuffer == null || addStatementBuffer.Count == 0) return;
			
			bool insertCombined = SupportsInsertCombined;
			
			Init();
			
			// Prevent recursion through NextId=>StatementCount
			StatementList statements = addStatementBuffer;
			addStatementBuffer = null;
			
			try {
				// Prefetch the IDs of all entities mentioned in statements.
				StringBuilder cmd = new StringBuilder();
				cmd.Append("SELECT id, value FROM ");
				cmd.Append(table);
				cmd.Append("_entities WHERE value IN (");
				Hashtable entseen = new Hashtable();
				bool hasEnts = false;
				for (int i = 0; i < statements.Count; i++) {
					Statement s = (Statement)statements[i];
					for (int j = 0; j < 4; j++) {
						Entity ent = s.GetComponent(j) as Entity;
						if (ent == null || ent.Uri == null) continue;
						if (entityCache.ContainsKey(ent.Uri)) continue;
						if (entseen.ContainsKey(ent.Uri)) continue;
						
						if (hasEnts)
							cmd.Append(" , ");
						EscapedAppend(cmd, ent.Uri);
						hasEnts = true;
						entseen[ent.Uri] = ent.Uri;
					}
				}
				if (hasEnts) {
					cmd.Append(");");
					if (Debug) Console.Error.WriteLine(cmd.ToString());
					using (IDataReader reader = RunReader(cmd.ToString())) {
						while (reader.Read()) {
                            Int64 id = reader.GetInt64(0);
							string uri = AsString(reader[1]);
							entityCache[uri] = id;
						}
					}
				}
				
				
				// Prefetch the IDs of all literals mentioned in statements.
				cmd.Length = 0;
				cmd.Append("SELECT id, hash FROM ");
				cmd.Append(table);
				cmd.Append("_literals WHERE hash IN (");
				bool hasLiterals = false;
				Hashtable litseen = new Hashtable();
				for (int i = 0; i < statements.Count; i++) {
					Statement s = (Statement)statements[i];
					Literal lit = s.Object as Literal;
					if (lit == null) continue;
					if (literalCache.ContainsKey(lit)) continue;
					
					string hash = GetLiteralHash(lit);
					if (litseen.ContainsKey(hash)) continue;
					
					if (hasLiterals)
						cmd.Append(" , ");
					EscapedAppend(cmd, hash);
					hasLiterals = true;
					litseen[hash] = lit;
				}
				if (hasLiterals) {
					cmd.Append(");");
					using (IDataReader reader = RunReader(cmd.ToString())) {
						while (reader.Read()) {
                            Int64 id = reader.GetInt64(0);
							string hash = AsString(reader[1]);
							Literal lit = (Literal)litseen[hash];
							literalCache[lit] = id;
						}
					}
				}
				
				StringBuilder entityInsertions = new StringBuilder();
				StringBuilder literalInsertions = new StringBuilder();
				if (insertCombined) entityInsertions.Append(INSERT_INTO_ENTITIES_VALUES);
				if (insertCombined) literalInsertions.Append(INSERT_INTO_LITERALS_VALUES);
				int entityInsertionsInitialLength = entityInsertions.Length;
				int literalInsertionsInitialLength = literalInsertions.Length;
				bool firstLiteralInsert = true, firstEntityInsert = true; // only used if insertCombined is true
				
				cmd = new StringBuilder();
				if (insertCombined)
					cmd.Append(INSERT_INTO_STATEMENTS_VALUES);

				for (int i = 0; i < statements.Count; i++) {
					Statement statement = (Statement)statements[i];

                    Int64 subj = GetResourceIdBuffer(statement.Subject, true, literalInsertions, entityInsertions, insertCombined, ref firstLiteralInsert, ref firstEntityInsert);
                    Int64 pred = GetResourceIdBuffer(statement.Predicate, true, literalInsertions, entityInsertions, insertCombined, ref firstLiteralInsert, ref firstEntityInsert);
                    Int64 objtype = ObjectType(statement.Object);
                    Int64 obj = GetResourceIdBuffer(statement.Object, true, literalInsertions, entityInsertions, insertCombined, ref firstLiteralInsert, ref firstEntityInsert);
                    Int64 meta = GetResourceIdBuffer(statement.Meta, true, literalInsertions, entityInsertions, insertCombined, ref firstLiteralInsert, ref firstEntityInsert);
					
					if (!insertCombined)
						cmd.Append(INSERT_INTO_STATEMENTS_VALUES);
					
					cmd.Append('(');
					cmd.Append(subj);
					cmd.Append(',');
					cmd.Append(pred);
					cmd.Append(',');
					cmd.Append(objtype);
					cmd.Append(',');
					cmd.Append(obj);
					cmd.Append(',');
					cmd.Append(meta);
					if (i == statements.Count-1 || !insertCombined)
						cmd.Append(");");
					else
						cmd.Append("),");
				}
				
				if (literalInsertions.Length > literalInsertionsInitialLength) {
					if (insertCombined)
						literalInsertions.Append(';');
					if (Debug) Console.Error.WriteLine(literalInsertions.ToString());
					RunCommand(literalInsertions.ToString());
				}
				
				if (entityInsertions.Length > entityInsertionsInitialLength) {
					if (insertCombined)
						entityInsertions.Append(';');
					if (Debug) Console.Error.WriteLine(entityInsertions.ToString());
					RunCommand(entityInsertions.ToString());
				}
				
				if (Debug) Console.Error.WriteLine(cmd.ToString());
				RunCommand(cmd.ToString());
			
			} finally {
				// Clear the array and reuse it.
				statements.Clear();
				addStatementBuffer = statements;
				entityCache.Clear();
				literalCache.Clear();
			}
		}
		public void Import(StatementSource source) {
			if (source == null) throw new ArgumentNullException();
			if (isImporting) throw new InvalidOperationException("Store is already importing.");
			
			Init();
			RunAddBuffer();
			
			cachedNextId = -1;
			NextId(); // get this before starting transaction because it relies on indexes which may be disabled
			
			addStatementBuffer = new StatementList();
			
			BeginTransaction();
			
			try {
				isImporting = true;
				source.Select(this);
			} finally {
				RunAddBuffer();
				EndTransaction();
				
				addStatementBuffer = null;
				isImporting = false;

				entityCache.Clear();
				literalCache.Clear();
			}
		}
		/*internal static void Escape(StringBuilder b) {
			b.Replace("\\", "\\\\");
			b.Replace("\"", "\\\"");
			b.Replace("\n", "\\n");
			b.Replace("%", "\\%");
			b.Replace("*", "\\*");
		}*/

		public override void Import(StatementSource source) {
			if (source == null) throw new ArgumentNullException();
			if (isImporting) throw new InvalidOperationException("Store is already importing.");
			
			Init();
			RunAddBuffer();
			
			cachedNextId = -1;
			addStatementBuffer = new StatementList();
			
			BeginTransaction();
			
			try {
				isImporting = true;
				base.Import(source);
			} finally {
				RunAddBuffer();
				EndTransaction();
				
				addStatementBuffer = null;
				isImporting = false;

				entityCache.Clear();
				literalCache.Clear();
			}
		}
 public Enumer(StatementList list)
 {
     this.list = list; index = -1;
 }
			public Enumer(StatementList list) { this.list = list; index = -1; }
		public MemoryStore(Statement[] statements) {
			this.statements = new StatementList(statements);
		}
		public MemoryStore() {
			statements = new StatementList();
		}
		private void ShorterList(ref StatementList list1, StatementList list2) {
			if (list2.Count < list1.Count)
				list1 = list2;
		}
        public void ProcessStore(MetadataStore store, Photo photo)
        {
            Hashtable desc = new Hashtable ();

            foreach (Statement stmt in store) {
                StatementList list = null;

                switch (stmt.Predicate.Uri) {
                case Description:
                case Headline:
                case Caption:
                case Title:
                case UserComment:
                    list = (StatementList) desc [stmt.Predicate];

                    if (list == null)
                        desc [stmt.Predicate] = list = new StatementList ();

                    list.Add (stmt);
                    break;

                case State:
                case City:
                case Country:
                case Location:
                case Source:
                    AddTagToPhoto (photo, stmt.Object as Literal, taginfo_table [stmt.Predicate] as TagInfo);
                    break;

                case Subject:
                case SupplementalCategories:
                case People:
                    if (!(stmt.Object is Entity))
                        break;

                    foreach (Statement tag in store.Select (new Statement (stmt.Object as Entity, null, null))) {

                        if (tag.Predicate != RdfType)
                            AddTagToPhoto (photo, tag.Object as Literal, null);

                    }
                    break;
                }
            }

            #if false
            /*
             * FIXME I need to think through what bengt was doing here before I put it in
             * it looks like we are doing some questionable repurposing of tags here and above
             */

            if (xmd.GetXmpBag_0 ("UserComment") != null)
                photo.Description = xmd.GetXmpBag_0 ("UserComment");

            // We want to construct the following : Description = <Headline> :: <Caption>

            // only check for more title/comment if you still do not have one.
            if ((photo.Description == null) || (photo.Description.Length == 0)) {
                if (xmd.GetXmpTag ("Headline") != null)
                    photo.Description = xmd.GetXmpTag ("Headline");
                // Lets add the Caption to the existing Description (Headline).
                if (xmd.GetXmpTag ("Caption") != null)
                    photo.Description += (( (photo.Description == null) ? "" : " :: ") + xmd.GetXmpTag ("Caption"));
            }

            // only check for more title/comment if you still do not have one.
            if ((photo.Description == null) || (photo.Description.Length == 0)) {
                if (xmd.GetXmpTag ("title") != null)
                    photo.Description = xmd.GetXmpTag ("title");
                // Lets add the Description  to the existing Description (Title).
                if (xmd.GetXmpTag ("description") != null)
                    photo.Description += (( (photo.Description == null) ? "" : " :: ") + xmd.GetXmpTag ("description"));
            }
            #endif
        }