Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fix SQL Server limit query to allow for DISTINCT and subqueries

  • Loading branch information...
commit 4ecd018c73e387904f78d81f1d327e34e905c5f1 1 parent 30dc433
Craig Mason authored

Showing 1 changed file with 41 additions and 8 deletions. Show diff stats Hide diff stats

  1. +41 8 lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php
49 lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php
@@ -680,10 +680,40 @@ public function getBooleanTypeDeclarationSQL(array $field)
680 680 protected function doModifyLimitQuery($query, $limit, $offset = null)
681 681 {
682 682 if ($limit > 0) {
683   - if ($offset == 0) {
684   - $query = preg_replace('/^(SELECT\s(DISTINCT\s)?)/i', '\1TOP ' . $limit . ' ', $query);
685   - } else {
686   - $orderby = stristr($query, 'ORDER BY');
  683 +
  684 + // Get thr ORDER BY clause
  685 + $matches = array();
  686 + $hasOrder = preg_match('/ORDER BY\s[^\)]*/i', $query, $matches);
  687 + $orderby = $hasOrder === 1 ? $matches[0] : '';
  688 +
  689 + // Check if this is a DISTINCT
  690 + $isDistinct = 0;
  691 + $query = preg_replace('/^SELECT DISTINCT/i', 'SELECT', $query, 1, $isDistinct);
  692 +
  693 + // Check if this is a wrapped query and we need to use the orderby alias
  694 + if($hasOrder === 1 && preg_match('/FROM\s*\([^\)]+\)/i', $query))
  695 + {
  696 + $orders = explode(',', preg_replace('/ORDER BY\s+/', '', $orderby));
  697 +
  698 + $aliasOrder = array();
  699 +
  700 +
  701 + foreach($orders as $order)
  702 + {
  703 + preg_match('/^([^\s]+)\s+(ASC|DESC)/', $order, $matches);
  704 +
  705 + $column = $matches[1];
  706 + $direction = $matches[2];
  707 +
  708 + $regex = sprintf('/%s\s+AS\s([A-Za-z0-9_]+)/', $column);
  709 + preg_match($regex, $query, $matches);
  710 + $alias = $matches[1];
  711 +
  712 + $aliasOrder[] = $alias . ' ' . $direction;
  713 + }
  714 +
  715 + $orderby = 'ORDER BY ' . implode(', ', $aliasOrder);
  716 + }
687 717
688 718 if ( ! $orderby) {
689 719 $over = 'ORDER BY (SELECT 0)';
@@ -692,15 +722,18 @@ protected function doModifyLimitQuery($query, $limit, $offset = null)
692 722 }
693 723
694 724 // Remove ORDER BY clause from $query
695   - $query = preg_replace('/\s+ORDER BY(.*)/', '', $query);
696   - $query = preg_replace('/^SELECT\s/', '', $query);
  725 + $query = preg_replace('/\s+ORDER BY([^\)]*)/', '', $query);
  726 +
  727 + // Remove SELECT and DISTINCT
  728 + $query = preg_replace('/^(SELECT\s(DISTINCT\s)?)/i', '', $query);
697 729
698 730 $start = $offset + 1;
699 731 $end = $offset + $limit;
700 732
701   - $query = "SELECT * FROM (SELECT ROW_NUMBER() OVER ($over) AS doctrine_rownum, $query) AS doctrine_tbl WHERE doctrine_rownum BETWEEN $start AND $end";
  733 + $distinctClause = $isDistinct === 1 ? 'DISTINCT' : '';
  734 + $query = sprintf("SELECT * FROM (SELECT ROW_NUMBER() OVER ($over) AS doctrine_rownum, * FROM ( SELECT %s $query) AS doctrine_tbl) AS doctrine_tbl2 WHERE doctrine_rownum BETWEEN $start AND $end", $distinctClause);
702 735 }
703   - }
  736 + //}
704 737
705 738 return $query;
706 739 }

0 comments on commit 4ecd018

Please sign in to comment.
Something went wrong with that request. Please try again.