diff --git a/ChangeLog b/ChangeLog
index fccbded1..22a9dea4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17194,3 +17194,6 @@
 	to be corrupt.
 	* Fixed a regression in the RDFeed service that caused detection
 	of feed	names to fail.
+2018-07-19 Fred Gleason <fredg@paravelsystems.com>
+	* Added a 'CAST_DOWNLOADS' table to the database.
+	* Incremented the database version to 294.
diff --git a/docs/tables/Makefile.am b/docs/tables/Makefile.am
index 2042ef11..9a140181 100644
--- a/docs/tables/Makefile.am
+++ b/docs/tables/Makefile.am
@@ -26,6 +26,7 @@ EXTRA_DIST = audio_cards.txt\
              audio_perms.txt\
              cart.txt\
              cartslots.txt\
+             cast_downloads.txt\
              clipboard.txt\
              clock_lines.txt\
              clock_perms.txt\
diff --git a/docs/tables/cast_downloads.txt b/docs/tables/cast_downloads.txt
new file mode 100644
index 00000000..7c695e28
--- /dev/null
+++ b/docs/tables/cast_downloads.txt
@@ -0,0 +1,12 @@
+                CAST_DOWNLOADS Table Layout for Rivendell
+
+The CAST_DOWNLOADS table holds data concerning downloads of podcast episodes.
+
+
+FIELD NAME           TYPE              REMARKS
+------------------------------------------------------------------------------
+ID                   int(10) unsigned  Primary key, Auto Increment
+FEED_KEY_NAME        char(8)           From FEEDS.KEY_NAME
+CAST_ID              int(10) unsigned  From PODCASTS.ID
+ACCESS_DATE          date
+ACCESS_COUNT         int(10) unsigned
diff --git a/lib/dbversion.h b/lib/dbversion.h
index 6c413589..473af794 100644
--- a/lib/dbversion.h
+++ b/lib/dbversion.h
@@ -24,7 +24,7 @@
 /*
  * Current Database Version
  */
-#define RD_VERSION_DATABASE 293
+#define RD_VERSION_DATABASE 294
 
 
 #endif  // DBVERSION_H
diff --git a/lib/rdfeedlog.cpp b/lib/rdfeedlog.cpp
index 17079366..e772f961 100644
--- a/lib/rdfeedlog.cpp
+++ b/lib/rdfeedlog.cpp
@@ -22,45 +22,27 @@
 
 #include <rdapplication.h>
 #include <rddb.h>
+#include <rdescape_string.h>
 #include <rdweb.h>
 
 #include "rdfeedlog.h"
 
-void RDCreateFeedLog(QString keyname)
-{
-  QString sql;
-  RDSqlQuery *q;
-
-  keyname.replace(" ","_");
-  sql=QString().sprintf("create table if not exists %s_FLG (\
-                         ID int unsigned primary key auto_increment,\
-                         CAST_ID int unsigned,\
-                         ACCESS_DATE date,\
-                         ACCESS_COUNT int unsigned default 0,\
-                         index CAST_ID_IDX(CAST_ID,ACCESS_DATE))",
-			(const char *)keyname);
-  q=new RDSqlQuery(sql);
-  delete q;
-}
-
-
 void RDDeleteFeedLog(QString keyname)
 {
-  keyname.replace(" ","_");
-  rda->dropTable(keyname+"_FLG");
+  QString sql=QString("delete from CAST_DOWNLOADS where ")+
+    "FEED_KEY_NAME=\""+RDEscapeString(keyname)+"\"";
+  RDSqlQuery::apply(sql);
 }
 
 
 void RDDeleteCastCount(QString keyname,unsigned cast_id)
 {
   QString sql;
-  RDSqlQuery *q;
 
-  keyname.replace(" ","_");
-  sql=QString().sprintf("delete from %s_FLG where CAST_ID=%u",
-			(const char *)keyname,cast_id);
-  q=new RDSqlQuery(sql);
-  delete q;
+  sql=QString("delete from CAST_DOWNLOADS where ")+
+    "FEED_KEY_NAME=\""+RDEscapeString(keyname)+"\" && "+
+    QString().sprintf("CAST_ID=%u",cast_id);
+  RDSqlQuery::apply(sql);
 }
 
 
@@ -88,45 +70,25 @@ void RDIncrementCastCount(QString keyname,unsigned cast_id)
 {
   QString sql;
   RDSqlQuery *q;
-  QDate current_date=QDate::currentDate();
+  QDate now=QDate::currentDate();
 
-  keyname.replace(" ","_");
-/*
-  FIXME: Table locking kills updates.  Why?
-
-  sql=QString().sprintf("lock tables %s_FLG read",(const char *)keyname);
-  q=new RDSqlQuery(sql);
-  delete q;
-*/
-  sql=QString().sprintf("select ACCESS_COUNT from %s_FLG where \
-                         (CAST_ID=%u)&&(ACCESS_DATE=\"%s\")",
-			(const char *)keyname,
-			cast_id,
-			(const char *)current_date.toString("yyyy-MM-dd"));
+  sql=QString("select ACCESS_COUNT from CAST_DOWNLOADS where ")+
+    "FEED_KEY_NAME=\""+RDEscapeString(keyname)+"\" && "+
+    QString().sprintf("(CAST_ID=%u)&&",cast_id)+
+    "(ACCESS_DATE=\""+RDEscapeString(now.toString("yyyy-MM-dd"))+"\")";
   q=new RDSqlQuery(sql);
   if(q->first()) {
-    sql=QString().sprintf("update %s_FLG set ACCESS_COUNT=%u where \
-                         (CAST_ID=%u)&&(ACCESS_DATE=\"%s\")",
-			  (const char *)keyname,
-			  q->value(0).toUInt()+1,cast_id,
-			  (const char *)current_date.toString("yyyy-MM-dd"));
+    sql=QString("update CAST_DOWNLOADS set ")+
+      QString().sprintf("ACCESS_COUNT=%u where ",q->value(0).toUInt()+1)+
+      QString().sprintf("(CAST_ID=%u)&&",cast_id)+
+      "(ACCESS_DATE=\""+RDEscapeString(now.toString("yyyy-MM-dd"))+"\")";
   }
   else {
-    sql=QString().sprintf("insert into %s_FLG set \
-                           CAST_ID=%u,\
-                           ACCESS_DATE=\"%s\",\
-                           ACCESS_COUNT=1",
-			  (const char *)keyname,
-			  cast_id,
-			  (const char *)current_date.toString("yyyy-MM-dd"));
+    sql=QString("insert into CAST_DOWNLOADS set ")+
+      QString().sprintf("CAST_ID=%u,",cast_id)+
+      "ACCESS_DATE=\""+RDEscapeString(now.toString("yyyy-MM-dd"))+"\","+
+      "ACCESS_COUNT=1";
   }
+  RDSqlQuery::apply(sql);
   delete q;
-  q=new RDSqlQuery(sql);
-  delete q;
-
-/*
-  sql="unlock tables";
-  q=new RDSqlQuery(sql);
-  delete q;
-*/
 }
diff --git a/lib/rdfeedlog.h b/lib/rdfeedlog.h
index 4b96ec8d..56c0337f 100644
--- a/lib/rdfeedlog.h
+++ b/lib/rdfeedlog.h
@@ -2,7 +2,7 @@
 //
 // Functions for manipulating RSS feed log tables.
 //
-//   (C) Copyright 2007,2016 Fred Gleason <fredg@paravelsystems.com>
+//   (C) Copyright 2007,2016-2018 Fred Gleason <fredg@paravelsystems.com>
 //
 //   This program is free software; you can redistribute it and/or modify
 //   it under the terms of the GNU General Public License version 2 as
@@ -23,7 +23,6 @@
 
 #include <qstring.h>
 
-void RDCreateFeedLog(QString keyname);
 void RDDeleteFeedLog(QString keyname);
 void RDDeleteCastCount(QString keyname,unsigned cast_id);
 void RDDeleteCastCount(unsigned feed_id,unsigned cast_id);
diff --git a/rdadmin/add_feed.cpp b/rdadmin/add_feed.cpp
index 8678df11..d2fcd4ed 100644
--- a/rdadmin/add_feed.cpp
+++ b/rdadmin/add_feed.cpp
@@ -173,7 +173,6 @@ void AddFeed::okData()
     "ITEM_XML=\""+RDEscapeString(DEFAULT_ITEM_XML)+"\"";
   q=new RDSqlQuery(sql);
   delete q;
-  RDCreateFeedLog(feed_keyname_edit->text());
   RDCreateAuxFieldsTable(feed_keyname_edit->text(),rda->config());
   sql=QString("select ID from FEEDS where ")+
     "KEY_NAME=\""+RDEscapeString(feed_keyname_edit->text())+"\"";
diff --git a/rdcastmanager/pick_report_dates.cpp b/rdcastmanager/pick_report_dates.cpp
index e789d8ba..d4746b52 100644
--- a/rdcastmanager/pick_report_dates.cpp
+++ b/rdcastmanager/pick_report_dates.cpp
@@ -215,13 +215,12 @@ void PickReportDates::GenerateSubscriptionReport(const QString &keyname,
   //
   // Data Rows
   //
-  QString keyname_esc=keyname;
-  keyname_esc.replace(" ","_");
   sql=QString("select ")+
     "ACCESS_DATE,"+   // 00
     "ACCESS_COUNT,"+  // 01
     "CAST_ID "+       // 02
-    "from "+keyname_esc+"_FLG where "+
+    "from CAST_DOWNLOADS where "+
+    "FEED_KEY_NAME=\""+RDEscapeString(keyname)+"\" && "+
     "(ACCESS_DATE>=\""+RDEscapeString(edit_startdate_edit->date().
 				      toString("yyyy-MM-dd"))+"\")&&"+
     "(ACCESS_DATE<=\""+RDEscapeString(edit_enddate_edit->date().
@@ -288,12 +287,11 @@ void PickReportDates::GenerateEpisodeReport(const QString &keyname,
   // Data Rows
   //
   unsigned total=0;
-  QString keyname_esc=keyname;
-  keyname_esc.replace(" ","_");
   sql=QString("select ")+
-    "ACCESS_DATE,"+
-    "ACCESS_COUNT "+
-    "from "+keyname_esc+"_FLG where "+
+    "ACCESS_DATE,"+   // 00
+    "ACCESS_COUNT "+  // 01
+    "from CAST_DOWNLOADS where "+
+    "FEED_KEY_NAME=\""+RDEscapeString(keyname)+"\" && "+
     "(ACCESS_DATE>=\""+RDEscapeString(edit_startdate_edit->date().
 				      toString("yyyy-MM-dd"))+"\")&&"+
     "(ACCESS_DATE<=\""+RDEscapeString(edit_enddate_edit->date().
diff --git a/utils/rddbmgr/revertschema.cpp b/utils/rddbmgr/revertschema.cpp
index 410c034e..ef66a266 100644
--- a/utils/rddbmgr/revertschema.cpp
+++ b/utils/rddbmgr/revertschema.cpp
@@ -38,6 +38,53 @@ bool MainObject::RevertSchema(int cur_schema,int set_schema,QString *err_msg) co
   //
 
 
+  //
+  // Revert 294
+  //
+  if((cur_schema==294)&&(set_schema<cur_schema)) {
+    sql=QString("select KEY_NAME from FEEDS");
+    q=new RDSqlQuery(sql);
+    while(q->next()) {
+      QString tablename=q->value(0).toString()+"_FLG";
+      tablename.replace(" ","_");
+      sql=QString("create table if not exists `")+tablename+"` ("+
+	"ID int unsigned primary key auto_increment,"+
+	"CAST_ID int unsigned,"+
+	"ACCESS_DATE date,"+
+	"ACCESS_COUNT int unsigned default 0,"+
+	"index CAST_ID_IDX(CAST_ID,ACCESS_DATE))";
+      if(!RDSqlQuery::apply(sql,err_msg)) {
+	return false;
+      }
+
+      sql=QString("select ")+
+	"CAST_ID,"+       // 00
+	"ACCESS_DATE,"+   // 01
+	"ACCESS_COUNT "+  // 02
+	"from CAST_DOWNLOADS where "+
+	"FEED_KEY_NAME=\""+RDEscapeString(q->value(0).toString())+"\" "+
+	"order by CAST_ID,ACCESS_DATE";
+      q1=new RDSqlQuery(sql,false);
+      while(q1->next()) {
+	sql=QString("insert into `")+tablename+"` set "+
+	  QString().sprintf("CAST_ID=%u,",q1->value(0).toUInt())+
+	  "ACCESS_DATE=\""+
+	  RDEscapeString(q1->value(1).toDate().toString("yyyy-MM-dd"))+"\","+
+	  QString().sprintf("ACCESS_COUNT=%u",q1->value(2).toUInt());
+	if(!RDSqlQuery::apply(sql,err_msg)) {
+	  return false;
+	}
+      }
+      delete q1;
+    }
+
+    if(!DropTable("CAST_DOWNLOADS",err_msg)) {
+      return false;
+    }
+
+    WriteSchemaVersion(--cur_schema);
+  }
+
   //
   // Revert 293
   //
diff --git a/utils/rddbmgr/schemamap.cpp b/utils/rddbmgr/schemamap.cpp
index 3f16ec39..8db9e034 100644
--- a/utils/rddbmgr/schemamap.cpp
+++ b/utils/rddbmgr/schemamap.cpp
@@ -132,7 +132,7 @@ void MainObject::InitializeSchemaMap() {
   global_version_map["2.17"]=268;
   global_version_map["2.18"]=272;
   global_version_map["2.19"]=275;
-  global_version_map["2.20"]=293;
+  global_version_map["2.20"]=294;
 }
 
 
diff --git a/utils/rddbmgr/updateschema.cpp b/utils/rddbmgr/updateschema.cpp
index 0281ab4e..83c8f62f 100644
--- a/utils/rddbmgr/updateschema.cpp
+++ b/utils/rddbmgr/updateschema.cpp
@@ -7797,6 +7797,54 @@ bool MainObject::UpdateSchema(int cur_schema,int set_schema,QString *err_msg) co
     WriteSchemaVersion(++cur_schema);
   }
 
+  if((cur_schema<294)&&(set_schema>cur_schema)) {
+    sql=QString("create table if not exists CAST_DOWNLOADS (")+
+      "ID int unsigned not null auto_increment primary key,"+
+      "FEED_KEY_NAME char(8) not null,"+
+      "CAST_ID int unsigned not null,"+
+      "ACCESS_DATE date not null,"+
+      "ACCESS_COUNT int unsigned not null default 0,"+
+      "unique index KEY_NAME_CAST_ID_DATE_IDX(FEED_KEY_NAME,CAST_ID,ACCESS_DATE))"+
+      db_table_create_postfix;
+    if(!RDSqlQuery::apply(sql,err_msg)) {
+      return false;
+    }
+
+    sql=QString("select KEY_NAME from FEEDS");
+    q=new RDSqlQuery(sql,false);
+    while(q->next()) {
+      QString tablename=q->value(0).toString()+"_FLG";
+      tablename.replace(" ","_");
+      sql=QString("select ")+
+	"CAST_ID,"+       // 00
+	"ACCESS_DATE,"+   // 01
+	"ACCESS_COUNT "+  // 02
+	"from `"+tablename+"` "+
+	"order by ACCESS_DATE";
+      q1=new RDSqlQuery(sql,false);
+      while(q1->next()) {
+	sql=QString("insert into CAST_DOWNLOADS set ")+
+	  "FEED_KEY_NAME=\""+RDEscapeString(q->value(0).toString())+"\","+
+	  QString().sprintf("CAST_ID=%u,",q1->value(0).toUInt())+
+	  "ACCESS_DATE=\""+
+	  RDEscapeString(q1->value(1).toDate().toString("yyyy-MM-dd"))+"\","+
+	  QString().sprintf("ACCESS_COUNT=%u",q1->value(2).toUInt());
+	if(!RDSqlQuery::apply(sql,err_msg)) {
+	  return false;
+	}
+      }
+      delete q1;
+      if(!DropTable(tablename,err_msg)) {
+	return false;
+      }
+    }
+    delete q;
+
+
+
+    WriteSchemaVersion(++cur_schema);
+  }
+
 
 
   //
diff --git a/utils/rdpurgecasts/rdpurgecasts.cpp b/utils/rdpurgecasts/rdpurgecasts.cpp
index d1fc2e07..9b31d082 100644
--- a/utils/rdpurgecasts/rdpurgecasts.cpp
+++ b/utils/rdpurgecasts/rdpurgecasts.cpp
@@ -143,10 +143,9 @@ void MainObject::PurgeCast(unsigned id)
       delete q1;
     }
     else {
-      QString keyname=q->value(2).toString();
-      keyname.replace(" ","_");
-      sql=QString().sprintf("delete from %s_FLG where CAST_ID=%d",
-			    (const char *)keyname,id);
+      sql=QString("delete from CAST_DOWNLOADS where ")+
+	"FEED_KEY_NAME=\""+RDEscapeString(q->value(2).toString())+"\" && "+
+	QString().sprintf("CAST_ID=%d",id);
       q1=new RDSqlQuery(sql);
       delete q1;
 
diff --git a/web/rdcastmanager/rdcastmanager.cpp b/web/rdcastmanager/rdcastmanager.cpp
index 69d67862..1f5e2053 100644
--- a/web/rdcastmanager/rdcastmanager.cpp
+++ b/web/rdcastmanager/rdcastmanager.cpp
@@ -1493,15 +1493,16 @@ void MainObject::ServeSubscriptionReport()
   line_colors[0]=RD_WEB_LINE_COLOR1;
   line_colors[1]=RD_WEB_LINE_COLOR2;
   int current_color=0;
-  QString keyname_esc=cast_key_name;
-  keyname_esc.replace(" ","_");
-  sql=QString().sprintf("select ACCESS_DATE,ACCESS_COUNT,CAST_ID from %s_FLG \
-                         where (ACCESS_DATE>=\"%s\")&&\
-                         (ACCESS_DATE<=\"%s\") \
-                         order by ACCESS_DATE,CAST_ID desc",
-			(const char *)keyname_esc,
-			(const char *)cast_start_date.toString("yyyy-MM-dd"),
-			(const char *)cast_end_date.toString("yyyy-MM-dd"));
+  sql=QString("select ")+
+    "ACCESS_DATE,"+   // 00
+    "ACCESS_COUNT,"+  // 01
+    "CAST_ID "+       // 02
+    "from CAST_DOWNLOADS where "+
+    "(ACCESS_DATE>=\""+
+    RDEscapeString(cast_start_date.toString("yyyy-MM-dd"))+"\")&&"+
+    "(ACCESS_DATE<=\""+
+    RDEscapeString(cast_end_date.toString("yyyy-MM-dd"))+"\" "+
+    "order by ACCESS_DATE,CAST_ID desc";
   q=new RDSqlQuery(sql);
   while(q->next()) {
     if(q->value(2).toUInt()==0) {
@@ -1660,16 +1661,17 @@ void MainObject::ServeEpisodeReport()
   line_colors[0]=RD_WEB_LINE_COLOR1;
   line_colors[1]=RD_WEB_LINE_COLOR2;
   int current_color=0;
-  QString keyname_esc=cast_key_name;
-  keyname_esc.replace(" ","_");
-  sql=QString().sprintf("select ACCESS_DATE,ACCESS_COUNT from %s_FLG \
-                         where (ACCESS_DATE>=\"%s\")&&\
-                         (ACCESS_DATE<=\"%s\")&& \
-                         (CAST_ID=%d) order by ACCESS_DATE",
-			(const char *)keyname_esc,
-			(const char *)cast_start_date.toString("yyyy-MM-dd"),
-			(const char *)cast_end_date.toString("yyyy-MM-dd"),
-			cast_cast_id);
+  sql=QString("select ")+
+    "ACCESS_DATE,"+   // 00
+    "ACCESS_COUNT "+  // 01
+    "from CAST_DOWNLOADS where "+
+    "FEED_KEY_NAME=\""+RDEscapeString(cast_key_name)+"\" && "+
+    "(ACCESS_DATE>=\""+
+    RDEscapeString(cast_start_date.toString("yyyy-MM-dd"))+"\")&&"+
+    "(ACCESS_DATE<=\""+
+    RDEscapeString(cast_end_date.toString("yyyy-MM-dd"))+"\")&&"+
+    QString().sprintf("(CAST_ID=%d) ",cast_cast_id)+
+    "order by ACCESS_DATE";
   q=new RDSqlQuery(sql);
   while(q->next()) {
     printf("<tr><td align=\"center\" bgcolor=\"%s\">%s</td>\n",