Answers.Body: <p>Thanks for that tip, Lindsey, but here's what happened: I changed <code>calendar37</code> to <code>calendar37_Occurrences</code> and then all three tables wouldn't uninstall.  It turns out that the issue is having a capital letter after the underscore.  So it seems like an "undocumented feature" that you can make plugin tables persist after uninstall by including a capital letter after the underscore.</p>
  
  <pre><code>return 'calendar37_Subsets';
  return 'calendar37_Views';
  </code></pre>
  
  <p>needed to become:</p>
  
  <pre><code>return 'calendar37_subsets';
  return 'calendar37_views';
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-12-08T19:02:41.203Z
Answers.Text: Glad you figured it out! I'd actually call that a bug more than a feature... If Craft decides to install a table, it should be equally willing to uninstall it.
Answers.UserDisplayName: Lindsey D
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-12-08T18:37:54.843Z
Answers.LastActivityDate: 2015-12-08T18:37:54.843Z
Answers.UserDisplayName: kr37
Answers.Body: <p>This is a little bit speculative, so let me know if it turns out to be incorrect...</p>
  
  <p>When you use a <strong>non-underscored</strong> Record name, you're telling Craft that this is the one-and-only, definitive Record. When you use an <strong>underscored</strong> Record name, you're telling Craft that this Record is one-of-many. I have a vague recollection of similar behavior with Variables or Controllers too.</p>
  
  <p>Hard to say if that would be considered a "bug" or a "feature". Pixel &amp; Tonic may have a sound reason why that restriction exists.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-12-08T07:40:33.723Z
Answers.LastActivityDate: 2015-12-08T07:40:33.723Z
Answers.UserDisplayName: Lindsey D
Body: <p>When uninstalling my plugin, only one table is removed. Two others are left behind.  Any suggestions what I'm doing wrong?  Could it be naming with and without the underscore?</p>
  
  <p>The good:</p>
  
  <pre><code>&lt;?php
  namespace Craft;
  
  class Calendar37Record extends BaseRecord
  {
      public function getTableName() {
          return 'calendar37';
      }
      protected function defineAttributes() { 
          return array(
              'event_id'   =&gt; AttributeType::Number,
              'dateYmd'    =&gt; AttributeType::String,
              'timestr'    =&gt; AttributeType::String,
              'alt_text'   =&gt; AttributeType::String,
              'css_class'  =&gt; AttributeType::String,
              'userJson'   =&gt; AttributeType::String,
          );
      }
      public function defineIndexes() {
          return array(
              array('columns' =&gt; array('event_id', 'dateYmd'), 'key' =&gt; true),
          );
      }
  }
  </code></pre>
  
  <p>and the bad:</p>
  
  <pre><code>&lt;?php
  namespace Craft;
  
  class Calendar37_SubsetsRecord extends BaseRecord
  {
      public function getTableName() {
          return 'calendar37_Subsets';
      }
      protected function defineAttributes() { 
          return array(
              'handle'              =&gt; AttributeType::String,
              'title'               =&gt; AttributeType::String,
              'categoriesToInclude' =&gt; AttributeType::String,
              'categoriesToExclude' =&gt; AttributeType::String,
              );
      }
      public function defineIndexes() {
          return array(
              array('columns' =&gt; array('handle'), 'unique' =&gt; true),
          );
      }
  }
  </code></pre>
  
  <p>Bad #2:</p>
  
  <pre><code>&lt;?php
  namespace Craft;
  
  class Calendar37_ViewsRecord extends BaseRecord
  {
      public function getTableName() {
          return 'calendar37_Views';
      }
      protected function defineAttributes() { 
          return array(
              'subsetId'     =&gt; AttributeType::String,
              'startDateYmd' =&gt; AttributeType::String,
              'endDateYmd'   =&gt; AttributeType::String,
              'htmlBefore'   =&gt; array(AttributeType::String, 'column' =&gt; ColumnType::Text, 'required' =&gt; false),
              'htmlAfter'    =&gt; array(AttributeType::String, 'column' =&gt; ColumnType::Text, 'required' =&gt; false),
          );
      }
      public function defineIndexes() {
          return array(
              array('columns' =&gt; array('subsetId', 'startDateYmd' ), 'key' =&gt; true),
          );
      }
  }
  </code></pre>
  
Tags: <plugin-development><records><uninstall>
Title: Plugin uninstall only removes one table
ThreadText: # Plugin uninstall only removes one table
  
  (Asked by: username_0 on 2015-12-08)
  
  When uninstalling my plugin, only one table is removed. Two others are left behind. Any suggestions what I'm doing wrong? Could it be naming with and without the underscore?
  
  The good:
  
  ```
  <?php
  namespace Craft;
  
  class Calendar37Record extends BaseRecord
  {
      public function getTableName() {
          return 'calendar37';
      }
      protected function defineAttributes() { 
          return array(
              'event_id'   => AttributeType::Number,
              'dateYmd'    => AttributeType::String,
              'timestr'    => AttributeType::String,
              'alt_text'   => AttributeType::String,
              'css_class'  => AttributeType::String,
              'userJson'   => AttributeType::String,
          );
      }
      public function defineIndexes() {
          return array(
              array('columns' => array('event_id', 'dateYmd'), 'key' => true),
          );
      }
  }
  
  ```
  
  and the bad:
  
  ```
  <?php
  namespace Craft;
  
  class Calendar37_SubsetsRecord extends BaseRecord
  {
      public function getTableName() {
          return 'calendar37_Subsets';
      }
      protected function defineAttributes() { 
          return array(
              'handle'              => AttributeType::String,
              'title'               => AttributeType::String,
              'categoriesToInclude' => AttributeType::String,
              'categoriesToExclude' => AttributeType::String,
              );
      }
      public function defineIndexes() {
          return array(
              array('columns' => array('handle'), 'unique' => true),
          );
      }
  }
  
  ```
  
  Bad #2:
  
  ```
  <?php
  namespace Craft;
  
  class Calendar37_ViewsRecord extends BaseRecord
  {
      public function getTableName() {
          return 'calendar37_Views';
      }
      protected function defineAttributes() { 
          return array(
              'subsetId'     => AttributeType::String,
              'startDateYmd' => AttributeType::String,
              'endDateYmd'   => AttributeType::String,
              'htmlBefore'   => array(AttributeType::String, 'column' => ColumnType::Text, 'required' => false),
              'htmlAfter'    => array(AttributeType::String, 'column' => ColumnType::Text, 'required' => false),
          );
      }
      public function defineIndexes() {
          return array(
              array('columns' => array('subsetId', 'startDateYmd' ), 'key' => true),
          );
      }
  }
  
  ```
  
  **Tags:** plugin-development, records, uninstall
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_0 on 2015-12-08. Score: 2 | Accepted answer
  
  Thanks for that tip, username_1, but here's what happened: I changed `calendar37` to `calendar37_Occurrences` and then all three tables wouldn't uninstall. It turns out that the issue is having a capital letter after the underscore. So it seems like an "undocumented feature" that you can make plugin tables persist after uninstall by including a capital letter after the underscore.
  
  ```
  return 'calendar37_Subsets';
  return 'calendar37_Views';
  
  ```
  
  needed to become:
  
  ```
  return 'calendar37_subsets';
  return 'calendar37_views';
  
  ```
  
  > **Comments:**
  > **username_1**: Glad you figured it out! I'd actually call that a bug more than a feature... If Craft decides to install a table, it should be equally willing to uninstall it.  
  
  ---
  
  ### Answer by username_1 on 2015-12-08. Score: 1
  
  This is a little bit speculative, so let me know if it turns out to be incorrect...
  
  When you use a **non-underscored** Record name, you're telling Craft that this is the one-and-only, definitive Record. When you use an **underscored** Record name, you're telling Craft that this Record is one-of-many. I have a vague recollection of similar behavior with Variables or Controllers too.
  
  Hard to say if that would be considered a "bug" or a "feature". Pixel & Tonic may have a sound reason why that restriction exists.
  
  
  ---
  
  