Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/** $Id: DBMSSQL.php 1262 2009-10-26 20:54:39Z francois $** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.** This software consists of voluntary contributions made by many individuals* and is licensed under the LGPL. For more information please see* <http://propel.phpdb.org>.*//*** This is used to connect to a MSSQL database.** @author Hans Lellelid <hans@xmpl.org> (Propel)* @version $Revision: 1262 $* @package propel.adapter*/class DBMSSQL extends DBAdapter {/*** This method is used to ignore case.** @param in The string to transform to upper case.* @return The upper case string.*/public function toUpperCase($in){return "UPPER(" . $in . ")";}/*** This method is used to ignore case.** @param in The string whose case to ignore.* @return The string in a case that can be ignored.*/public function ignoreCase($in){return "UPPER(" . $in . ")";}/*** Returns SQL which concatenates the second string to the first.** @param string String to concatenate.* @param string String to append.* @return string*/public function concatString($s1, $s2){return "($s1 + $s2)";}/*** Returns SQL which extracts a substring.** @param string String to extract from.* @param int Offset to start from.* @param int Number of characters to extract.* @return string*/public function subString($s, $pos, $len){return "SUBSTRING($s, $pos, $len)";}/*** Returns SQL which calculates the length (in chars) of a string.** @param string String to calculate length of.* @return string*/public function strLength($s){return "LEN($s)";}/*** @see DBAdapter::quoteIdentifier()*/public function quoteIdentifier($text){return '[' . $text . ']';}/*** @see DBAdapter::random()*/public function random($seed = null){return 'rand('.((int) $seed).')';}/*** Simulated Limit/Offset* This rewrites the $sql query to apply the offset and limit.* @see DBAdapter::applyLimit()* @author Justin Carlson <justin.carlson@gmail.com>* @author Benjamin Runnels <kraven@kraven.org>*/public function applyLimit(&$sql, $offset, $limit){// make sure offset and limit are numericif (!is_numeric($offset) || !is_numeric($limit)){throw new Exception("DBMSSQL::applyLimit() expects a number for argument 2 and 3");}//split the select and from clauses out of the original query$selectSegment = array();preg_match('/\Aselect(.*)from(.*)/si',$sql,$selectSegment);if (count($selectSegment)==3){$selectStatement = trim($selectSegment[1]);$fromStatement = trim($selectSegment[2]);}else{throw new Exception("DBMSSQL::applyLimit() could not locate the select statement at the start of the query. ");}//handle the ORDER BY clause if present$orderSegment = array();preg_match('/order by(.*)\Z/si',$fromStatement,$orderSegment);if (count($orderSegment)==2){//remove the ORDER BY from $sql$fromStatement = trim(str_replace($orderSegment[0], '', $fromStatement));//the ORDER BY clause is used in our inner select ROW_NUMBER() clause$countColumn = trim($orderSegment[1]);}//setup inner and outer select selects$innerSelect = '';$outerSelect = '';foreach(explode(', ',$selectStatement) as $selCol) {@list($column,,$alias) = explode(' ', $selCol);//make sure the current column isn't * or an aggregateif ($column!='*' && !strstr($column,'(')) {//we can use the first non-aggregate column for ROW_NUMBER() if it wasn't already set from an order by clauseif(!isset($countColumn)) {$countColumn = $column;}//add an alias to the inner select so all columns will be unique$innerSelect .= $column." AS [$column],";//use the alias in the outer select if one was present on the original select columnif(isset($alias)) {$outerSelect .= "[$column] AS $alias,";} else {$outerSelect .= "[$column],";}} else {//agregate columns must always have an alias clauseif(!isset($alias)) {throw new Exception("DBMSSQL::applyLimit() requires aggregate columns to have an Alias clause");}//use the whole aggregate column in the inner select$innerSelect .= "$selCol,";//only add the alias for the aggregate to the outer select$outerSelect .= "$alias,";}}//check if we got this far and still don't have a viable column to user with ROW_NUMBER()if(!isset($countColumn)) {throw new Exception("DBMSSQL::applyLimit() requires an ORDER BY clause or at least one non-aggregate column in the select statement");}//ROW_NUMBER() starts at 1 not 0$from = ($offset+1);$to = ($limit+$offset);//substring our select strings to get rid of the last comma and add our FROM and SELECT clauses$innerSelect = "SELECT ROW_NUMBER() OVER(ORDER BY $countColumn) AS RowNumber, ".substr($innerSelect,0,-1).' FROM';$outerSelect = 'SELECT '.substr($outerSelect,0,-1).' FROM';// build the query$sql = "$outerSelect ($innerSelect $fromStatement) AS derivedb WHERE RowNumber BETWEEN $from AND $to";}}