sfy
sfy

Reputation: 3228

What's the purpose of this bitwise AND operator?

The code is basic php code for a cms,It read Mysql content to render web page based on three different methods ,by id,name or special type(index page,sitemap page ...).But I can't understand this line " $r=dbRow("select * from pages where special&$v limit 1");" what is the bitwise AND supposed to do ?

<?php
class Page{
    static $instances             = array();
    static $instancesByName     = array();
    static $instancesBySpecial   = array();
    function __construct($v,$byField=0,$fromRow=0,$pvq=0){
        # byField: 0=ID; 1=Name; 3=special
        if (!$byField && is_numeric($v)){ // by ID
            $r=$fromRow?$fromRow:($v?dbRow("select * from pages where id=$v limit 1"):array());
        }
        else if ($byField == 1){ // by name
            $name=strtolower(str_replace('-','_',$v));
            $fname='page_by_name_'.md5($name);
            $r=dbRow("select * from pages where name like '".addslashes($name)."' limit 1");
        }
        else if ($byField == 3 && is_numeric($v)){ // by special
            $fname='page_by_special_'.$v;
            $r=dbRow("select * from pages where special&$v limit 1");
        }
        else return false;
        if(!count($r || !is_array($r)))return false;
        if(!isset($r['id']))$r['id']=0;
        if(!isset($r['type']))$r['type']=0;
        if(!isset($r['special']))$r['special']=0;
        if(!isset($r['name']))$r['name']='NO NAME SUPPLIED';
        foreach ($r as $k=>$v) $this->{$k}=$v;
        $this->urlname=$r['name'];
        $this->dbVals=$r;
        self::$instances[$this->id] =& $this;
        self::$instancesByName[preg_replace('/[^a-z0-9]/','-',strtolower($this->urlname))] =& $this;
        self::$instancesBySpecial[$this->special] =& $this;
        if(!$this->vars)$this->vars='{}';
        $this->vars=json_decode($this->vars);
    }
    function getInstance($id=0,$fromRow=false,$pvq=false){
        if (!is_numeric($id)) return false;
        if (!@array_key_exists($id,self::$instances)) self::$instances[$id]=new Page($id,0,$fromRow,$pvq);
        return self::$instances[$id];
    }
    function getInstanceByName($name=''){
        $name=strtolower($name);
        $nameIndex=preg_replace('#[^a-z0-9/]#','-',$name);
        if(@array_key_exists($nameIndex,self::$instancesByName))return self::$instancesByName[$nameIndex];
        self::$instancesByName[$nameIndex]=new Page($name,1);
        return self::$instancesByName[$nameIndex];
    }
    function getInstanceBySpecial($sp=0){
        if (!is_numeric($sp)) return false;
        if (!@array_key_exists($sp,$instancesBySpecial)) $instancesBySpecial[$sp]=new Page($sp,3);
        return $instancesBySpecial[$sp];
    }
}

Upvotes: 1

Views: 381

Answers (1)

eggyal
eggyal

Reputation: 125865

It appears that pages.special contains a bit field (that is, each bit position in its values would flag some application-specific property).

Then, to find records that have certain properties, one would perform a bitwise AND operation with the desired "mask"—bit positions in the result are set only if the same position was set in both the value and the mask. A complete truth-table for a 2-bit value would look like this:

+---------+------+------------+
|  value  | mask | value&mask |
+---------+------+------------+
|    0b00 | 0b00 |       0b00 |
|    0b01 | 0b00 |       0b00 |
|    0b10 | 0b00 |       0b00 |
|    0b11 | 0b00 |       0b00 |
|    0b00 | 0b01 |       0b00 |
|    0b01 | 0b01 |       0b01 |
|    0b10 | 0b01 |       0b00 |
|    0b11 | 0b01 |       0b01 |
|    0b00 | 0b10 |       0b00 |
|    0b01 | 0b10 |       0b00 |
|    0b10 | 0b10 |       0b10 |
|    0b11 | 0b10 |       0b10 |
|    0b00 | 0b11 |       0b00 |
|    0b01 | 0b11 |       0b01 |
|    0b10 | 0b11 |       0b10 |
|    0b11 | 0b11 |       0b11 |
+---------+------+------------+

For example, suppose the lowest-order bit is a flag that the respective page "is readonly"; and the next bit that the page "requires moderation"—a value of (decimal) 2, or 0b10, would indicate that the page is not readonly but does require moderation. So, to find all pages that either are readonly or require moderation, one could do:

SELECT * FROM pages WHERE (special & 0b11) != 0

Because MySQL doesn't have true boolean types (but instead treats zero as false and non-zero as true), the filter expression can be abbreviated:

SELECT * FROM pages WHERE special & 0b11

We could also state the mask in decimal, rather than binary, form:

SELECT * FROM pages WHERE special & 3

And, if so desired, apply a LIMIT to the query (although in the absence of an ORDER BY clause, the result is indeterminate):

SELECT * FROM pages WHERE special&3 LIMIT 1

Given that is all we have to work with (from the code that you have shown), we can only say the following:

The query selects all columns of an indeterminate record from the pages table for which the value of special has at least one of the same bits set as in the mask $v.

Since the semantics of special and $v (and the bit positions within them) are application-specific, it is impossible for one to say anything more without a deeper understanding of your application.

Note that, whilst compact, filtering using a mask on a bit field is not sargable—so this tends to be very poor database design.

Upvotes: 3

Related Questions