Problem/Motivation
The SQL Server driver is not providing transparent compatibility when managing crap indexes. SQL Server is strict about bad design patterns.
What is a crap index?
- An index that involves non indexable data fields such as TEXT.
- An index that specifies a maximum indexable length for a field so that the overal index size will fit in size constraints (such as OHHH I cannot index this nvarchar(max) column, so let's index only the first 50 bytes)
#2390945: SQL Server - PDOException: SQLSTATE[42000] when attempting update
#2457045: Index on submission data incompatible with MS SQL Server
- Any index that has a total size > 900 bytes.
Right now, during table creation, the driver is simply failing silently when creating indexes:
// Create the indexes but ignore any error during the creation. We do that
// do avoid pulling the carpet under modules that try to implement indexes
// with invalid data types (long columns), before we come up with a better
// solution.
if (isset($table['indexes']) && is_array($table['indexes'])) {
foreach ($table['indexes'] as $key_name => $key) {
try {
$this->addIndex($name, $key_name, $key);
}
catch (Exception $e) {
// Log the exception but do not rollback the transaction.
watchdog_exception('database', $e);
}
}
}
In other parts of the API specific to index management, it does throw exceptions if the index cannot be created.
Part of the problem also stems from the fact that type mappings do not resemble their MySQL sibblings in size:
'text:tiny' => 'nvarchar(max)',
'text:small' => 'nvarchar(max)',
'text:medium' => 'nvarchar(max)',
'text:big' => 'nvarchar(max)',
'text:normal' => 'nvarchar(max)',
This mappings should be revised to make the storage type closer to what it is in MySQL.
Proposed resolution
[1] Make the driver consitent and silently fail when an index cannot be created.
AND
[2] Revise type mappings
Remaining tasks
All
User interface changes
None
API changes
None
Original report by []
My setup:
Drupal 7.17 / IIS 7.5 / MS SQL Server 2008
My issue:
I just tried to update my version of Drupal from 7.16 to 7.17, and received the following error:
The following updates returned messages
aggregator module
Update #7003
Failed: PDOException: SQLSTATE[42000]: [Microsoft][SQL Server Native Client 10.0][SQL Server]Column 'url' in table 'aggregator_feed' is of a type that is invalid for use as a key column in an index.: CREATE INDEX url_idx ON [{aggregator_feed}] (url); Array ( ) in db_add_index() (line 2912 of C:\inetpub\wwwroot\drupal\includes\database\database.inc).There were 4 pending updates listed, and all but the "aggregator module" update went through fine:
system module
7076 - Convert menu_links query strings into arrays.
7077 - Revert {file_managed}.filename changed to a binary column.
aggregator module
7003 - Increase the length of {aggregator_feed}.url.
locale module
7005 - Increase {locales_languages}.formula column's length.
If anyone has a solution that can fix this issue, that would be great. Thanks for any help.
| Comment | File | Size | Author |
|---|---|---|---|
| #18 | _workaround-aggregator_feed-url900-1839938-18.patch | 1.41 KB | Uncle_Code_Monkey |
Comments
Comment #1
David_Rothstein commentedSounds like this might be a bug with http://drupal.org/project/sqlsrv (I'm assuming you're using that) rather than Drupal core?
Comment #2
katannshaw commentedI'm using Drupal core with the contributed sqlsrv module. So the updated files that were referenced in the error are from the Drupal core's ZIP file. Since I used these core files, and since the error references a core module, wouldn't that be the location for this error?
When I started this project, I was told that Drupal 7+ and its updates was designed to be able to work with several database types because it was database-neutral. I was told that we wouldn't be having these types of issues regarding not being able to change a table column's properties, because my use of MS SQL and another person'S MySQL or PostGreSQL. Am I incorrect?
I appreciate your help on this. Thanks!
Comment #3
Graham_W commentedI've an error on the same module.
An AJAX HTTP request terminated abnormally. Debugging information follows. Path: http://example.com/drupal/update.php?op=selection&token=-pj8hsl9QDTfkmOZ... StatusText: ResponseText: ReadyState: 4
Oddly, the near enough identical test site upgraded OK.
I moved the database over and all was well.
Not sure what the differences are as the only things I had done on the test site were to add Rubik and Tao themes and enable Rubik for admin, and I'd installed the Apps and Levelten_apps modules in preparation for testing some of their apps.
Comment #4
katannshaw commentedNot sure if the issue is within core or the sqlsrv module, so I thought I'd check:
The datatype for the 'url' column is nvarchar(MAX) in the 'aggregator_feed' table referenced by the error posted originally. Does the sqlsrv driver module need to be adjusted to fix this issue?
I did find these similar issues via a Google search:
Allow aggregator feed URLs longer than 255 characters
Stack Overflow: is of a type that is invalid for use as a key column in an index
Comment #5
omegamonk commentedjayhawkfan75:
I am working on replicating the issue.
Comment #6
katannshaw commentedThank you omegamonk. I appreciate your help.
FYI: I'm still getting the error when running the update script, but the site still works properly so far.
Comment #7
katannshaw commented@omegamonk: I'm not sure how I could help, but would you like some assistance in replicating this issue? This error is keeping my database update out-of-date even though I've been able to update other modules without a problem.
Comment #8
chezwel commentedI'm also getting the same error after the most recent security update. The site works properly but still getting the database update prompt. I'm also using the sqlsrv module.
Thanks for any help resolving this issue.
Comment #9
gRezes commentedI just updated my Acquia Drupal from 7.15 to 7.18 and I am receiving the same URL index error in the database update.
Specifically my error is:
Failed: PDOException: SQLSTATE[42000]: [Microsoft][SQL Server Native Client 11.0][SQL Server]
Column 'url' in table 'aggregator_feed' is of a type that is invalid for use as a key column
in an index.: CREATE INDEX url_idx ON [{aggregator_feed}] (url); Array ( ) in db_add_index()
(line 2912 of C:\inetpub\wwwroot\acquia-drupal7\includes\database\database.inc).
Any idea how to run this manually to remove the error and complete the database schema update?
Comment #10
vitesse commentedGetting the same issue trying to update 7.16 -> 7.18
I'm not running Aquia, but rather the drupal.org core along with the Microsoft sqlsrvr libraries. As noted above, things were working fine until trying update 7.18.
Failed: PDOException: SQLSTATE[42000]: [Microsoft][SQL Server Native Client 11.0][SQL Server]
Column 'url' in table 'aggregator_feed' is of a type that is invalid for use as a key column
in an index.: CREATE INDEX url_idx ON [{aggregator_feed}] (url); Array ( ) in db_add_index()
(line 2912 of C:\inetpub\wwwroot\drupal7\includes\database\database.inc).
Looking at the list of changes here, the authors make reference [CHANGELOG.txt] to changing the SQL type of [aggregator_feed].[url] from a varchar(MAX) to a TEXT (though, since the two are functionally equivalent, I can't imagine why). I'm not a MySQL guy so perhaps that's the reasoning.... The error message doesn't seem to concern this change though, and instead infers that the update is trying to make the [url] an index.
Anybody have more insight?
Comment #11
vitesse commentedDid some more testing today,
The problem appears to be that MS SQL sever does not want to index columns of type [text].
Will produce the following error (look familiar?)
This press's further the case that SQL types [TEXT] and [IMAGE] are going to disappear soon. This has been news for more than 5 or 6 years now to MS SQL developers, but some Drupal developers are still hanging onto them. Would appreciate someone looking into MySQL on this and I bet, that it allows indexing on [TEXT] columns.
More insight as it happens.
Comment #12
gRezes commentedSeems to still be a problem with drupal version 7.19. Is this scheduled to be fixed? Or is there a workaround?
Comment #13
katannshaw commented@gRezes: I'm still getting the same error with Drupal core version 7.19 as well, and unfortunately no one appears to be working on a solution. I'll update the priority as it appears to be affecting several users.
Comment #14
katannshaw commentedComment #15
omegamonk commented@jayhawkfan75: My apologies if it appears that no one is working on a solution. I am trying to get up to speed on the project, overall. As @Vitesse indicated, this is an issue because Microsoft SQL does not support indexing a nonkey text field (http://msdn.microsoft.com/en-us/library/ms190806.aspx). I am working on an alternative solution for this issue.
Comment #16
katannshaw commented@omegamonk: Awesome news! Thanks so much for the update and your help on this issue. Let me know if/when you need for me to test anything out.
Comment #17
Uncle_Code_Monkey commentedIn the table
aggregator_feed, the column "url" changed from type "varchar(255)" to "nvarchar(MAX)" and SQL Server is not capable of indexing anything larger than "nvarchar(900)" for key columns.I am not quite sure how to fix such an issue.
Comment #18
Uncle_Code_Monkey commentedI created a workaround patch that will change the Core module Aggregator such that column
urlis a "varchar(900)" instead of "text".Again, this is just a workaround to get my site up and running that I thought I would share, it is not a suggested fix.
Comment #19
xenphibian commented@Uncle Code Monkey, Technically, SQL Server can only create an index with a TOTAL of 900 bytes for all keys. So, if all of the other key column sizes added up to 900 bytes, then you couldn't even add an nvarchar(1) as a part of the key. You COULD, however, include the column in the INCLUDE clause of the CREATE INDEX statement, as those are not counted when calculating the key size.
But, that's not the real problem, I think. The real problem is that TEXT fields aren't allowed to be a part of indexes at all.
Your patch corrects the TEXT issue (for small, ordinary URLs of less than 900 bytes), but not if you have a URL of greater than that, which couldn't be accommodated at all. It also wouldn't fix other, similar situations with other keys.
I see at least one way this could be fixed.
Create a view with a table behind the scenes that keeps the first 255 characters of the [url] column as a VARCHAR[255]. When actually querying the view named [aggregator_feed] we actually would get [aggregator_feed_behind].[url_key] + [aggregator_feed_behind].[url_text] AS [url]. The [url_key] column would be the first 255 and the [url_text] column would be the remaining characters (if any). The view could then have the index on [url_key] and everything's hunky dory, WITH clauses would still work properly.
This should be fairly easy to generalize for all indexed TEXT fields, but I'd be interested in seeing performance tests (I bet it'd still out perform MySQL handily because most of the time there won't be anything after the 255 characters, so no performance impact when querying). I have used this technique before without performance degradation on high demand, big data databases.
Comment #20
katannshaw commentedI just ran the patch from #18 and it fixed my issue. Thanks Uncle_Code_Monkey! Would it be better to have the datatype set to nvarchar(MAX)?
Also, is there an update on a permanent fix for this issue within the SQL Server Driver module? It's a pretty old issue.
Comment #21
Uncle_Code_Monkey commentednvarchar(MAX) did not work, only when I used nvarchar(900) did things work for me. I don't like the solution which is why I consider it a workaround until someone with more experience dealing with these issues creates a proper fix.
Comment #22
katannshaw commentedGood to know. I really appreciate the workaround patch, and hopefully we hear something soon from the maintainers about this being fixed.
Comment #23
terri8502 commentedI just upgraded to 7.23 and this is still an issue. I saw the patch above and am going to try and figure out how to install and use it (I've never installed a patch before)... does anyone have any news as to whether this is going to be fixed? It looks like it is still "unassigned", does that mean no one is looking at it? Also, if I install the patch and then upgrade to a newer core version (when one becomes available), will I need to reapply? BTW - would this be considered an issue for SQL module or for Aggregator?
Comment #24
gRezes commentedI just updated to 7.23 and this is still an issue. I just go into aggregator.install and comment out the 7003 update code.
Comment #25
katannshaw commented@terri8502: I've not received the error since I applied the temporary fix from #18. I'm thinking that this is a SQL Server driver issue from omegamonk's comment, but I haven't heard anything more about that since January it appears. Let me know how it worked out for you.
@gRezes: Thanks for your suggestion; I'll have to give that a try. It would be nice for this issue to be resolved.
@omegamonk: Has there been any progress on this issue? Thanks for your attention, I appreciate that.
Comment #26
Renee S commented@jayhawkfan75: This is happening for us Oracle users too!
Comment #27
katannshaw commentedInteresting, so that would mean that it's an Aggregator issue if it's not working with SQL Server and Oracle, correct?
Comment #28
Renee S commentedIt might not be; it's also possible it's just the only (or the first) module to do an action that doesn't work in non-MySQL that hasn't been accounted for by the driver. Oracle has different varchar lengths too.
Comment #29
gRezes commentedWhen I try comment #18 with varchar(900) or even smaller varchar(890) I receieve the error message:
aggregator module
Update #7003
Failed: PDOException: SQLSTATE[42000]: [Microsoft][SQL Server Native Client 11.0][SQL Server]Cannot create a row of size 8074 which is greater than the allowable maximum row size of 8060.: ALTER TABLE {aggregator_feed} ALTER COLUMN [url] nvarchar(890) NOT NULL; Array ( ) in db_change_field() (line 3017 of C:\inetpub\wwwroot\acquia-drupal7\includes\database\database.inc).
Therefore I just comment out the 7003 update. But, I don't use the aggregator module.
Comment #30
david_garcia commentedThere is some tough work fixing this.
There are two options:
1. Use full text indexes, these are fully transparent to and easier to implement but... it will be an aditional requierement to have full-text-search enabled.
2. When the database layer requests an index on a column that can be larger than 900bytes:
(http://www.brentozar.com/archive/2013/05/indexing-wide-keys-in-sql-server/)
- Create a computed column based on the original column/s (CHECKSUM OR SHA2)
- Create the index on the computed column
(up to here easy)
- Whenever there is an equality comparison modify queries to work on the computed column
This is showing again with a recent WEBFORM module update.
Comment #31
katannshaw commentedAs david_garcia mentioned, this is happening with update 7419 of the Webform module as well. So I'm updating the title and version.
Maintainers: Has there been any recent work on this issue?
@david_garcia: If you'd like me to try any patches or other suggestions, I'm ready to do so. Thanks for your help on this.
Comment #32
katannshaw commentedIssue SQL Server - PDOException: SQLSTATE[42000] when attempting update marked as a duplicate of this issue.
Comment #33
david_garcia commentedThe last version of the driver is already "compressing" primary keys when it detects the size exceeds SQL Server limits, that could be a strategy to use when creating regular indexes.
Comment #34
david_garcia commentedComment #35
david_garcia commentedComment #36
avpadernoComment #37
beakerboyThe 7.x branch is unsupported