MediaWiki
REL1_23
|
00001 <?php 00028 class DatabaseSqlite extends DatabaseBase { 00030 private static $fulltextEnabled = null; 00031 00033 public $mDatabaseFile; 00034 00036 protected $mAffectedRows; 00037 00039 protected $mLastResult; 00040 00042 protected $mConn; 00043 00045 protected $lockMgr; 00046 00047 function __construct( $p = null ) { 00048 global $wgSharedDB, $wgSQLiteDataDir; 00049 00050 if ( !is_array( $p ) ) { // legacy calling pattern 00051 wfDeprecated( __METHOD__ . " method called without parameter array.", "1.22" ); 00052 $args = func_get_args(); 00053 $p = array( 00054 'host' => isset( $args[0] ) ? $args[0] : false, 00055 'user' => isset( $args[1] ) ? $args[1] : false, 00056 'password' => isset( $args[2] ) ? $args[2] : false, 00057 'dbname' => isset( $args[3] ) ? $args[3] : false, 00058 'flags' => isset( $args[4] ) ? $args[4] : 0, 00059 'tablePrefix' => isset( $args[5] ) ? $args[5] : 'get from global', 00060 'schema' => 'get from global', 00061 'foreign' => isset( $args[6] ) ? $args[6] : false 00062 ); 00063 } 00064 $this->mDBname = $p['dbname']; 00065 parent::__construct( $p ); 00066 // parent doesn't open when $user is false, but we can work with $dbName 00067 if ( $p['dbname'] && !$this->isOpen() ) { 00068 if ( $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ) ) { 00069 if ( $wgSharedDB ) { 00070 $this->attachDatabase( $wgSharedDB ); 00071 } 00072 } 00073 } 00074 00075 $this->lockMgr = new FSLockManager( array( 'lockDirectory' => "$wgSQLiteDataDir/locks" ) ); 00076 } 00077 00081 function getType() { 00082 return 'sqlite'; 00083 } 00084 00090 function implicitGroupby() { 00091 return false; 00092 } 00093 00105 function open( $server, $user, $pass, $dbName ) { 00106 global $wgSQLiteDataDir; 00107 00108 $this->close(); 00109 $fileName = self::generateFileName( $wgSQLiteDataDir, $dbName ); 00110 if ( !is_readable( $fileName ) ) { 00111 $this->mConn = false; 00112 throw new DBConnectionError( $this, "SQLite database not accessible" ); 00113 } 00114 $this->openFile( $fileName ); 00115 00116 return $this->mConn; 00117 } 00118 00126 function openFile( $fileName ) { 00127 $err = false; 00128 00129 $this->mDatabaseFile = $fileName; 00130 try { 00131 if ( $this->mFlags & DBO_PERSISTENT ) { 00132 $this->mConn = new PDO( "sqlite:$fileName", '', '', 00133 array( PDO::ATTR_PERSISTENT => true ) ); 00134 } else { 00135 $this->mConn = new PDO( "sqlite:$fileName", '', '' ); 00136 } 00137 } catch ( PDOException $e ) { 00138 $err = $e->getMessage(); 00139 } 00140 00141 if ( !$this->mConn ) { 00142 wfDebug( "DB connection error: $err\n" ); 00143 throw new DBConnectionError( $this, $err ); 00144 } 00145 00146 $this->mOpened = !!$this->mConn; 00147 # set error codes only, don't raise exceptions 00148 if ( $this->mOpened ) { 00149 $this->mConn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT ); 00150 # Enforce LIKE to be case sensitive, just like MySQL 00151 $this->query( 'PRAGMA case_sensitive_like = 1' ); 00152 00153 return $this->mConn; 00154 } 00155 00156 return false; 00157 } 00158 00163 protected function closeConnection() { 00164 $this->mConn = null; 00165 00166 return true; 00167 } 00168 00175 public static function generateFileName( $dir, $dbName ) { 00176 return "$dir/$dbName.sqlite"; 00177 } 00178 00183 function checkForEnabledSearch() { 00184 if ( self::$fulltextEnabled === null ) { 00185 self::$fulltextEnabled = false; 00186 $table = $this->tableName( 'searchindex' ); 00187 $res = $this->query( "SELECT sql FROM sqlite_master WHERE tbl_name = '$table'", __METHOD__ ); 00188 if ( $res ) { 00189 $row = $res->fetchRow(); 00190 self::$fulltextEnabled = stristr( $row['sql'], 'fts' ) !== false; 00191 } 00192 } 00193 00194 return self::$fulltextEnabled; 00195 } 00196 00201 static function getFulltextSearchModule() { 00202 static $cachedResult = null; 00203 if ( $cachedResult !== null ) { 00204 return $cachedResult; 00205 } 00206 $cachedResult = false; 00207 $table = 'dummy_search_test'; 00208 00209 $db = new DatabaseSqliteStandalone( ':memory:' ); 00210 00211 if ( $db->query( "CREATE VIRTUAL TABLE $table USING FTS3(dummy_field)", __METHOD__, true ) ) { 00212 $cachedResult = 'FTS3'; 00213 } 00214 $db->close(); 00215 00216 return $cachedResult; 00217 } 00218 00230 function attachDatabase( $name, $file = false, $fname = __METHOD__ ) { 00231 global $wgSQLiteDataDir; 00232 if ( !$file ) { 00233 $file = self::generateFileName( $wgSQLiteDataDir, $name ); 00234 } 00235 $file = $this->addQuotes( $file ); 00236 00237 return $this->query( "ATTACH DATABASE $file AS $name", $fname ); 00238 } 00239 00246 function isWriteQuery( $sql ) { 00247 return parent::isWriteQuery( $sql ) && !preg_match( '/^ATTACH\b/i', $sql ); 00248 } 00249 00256 protected function doQuery( $sql ) { 00257 $res = $this->mConn->query( $sql ); 00258 if ( $res === false ) { 00259 return false; 00260 } else { 00261 $r = $res instanceof ResultWrapper ? $res->result : $res; 00262 $this->mAffectedRows = $r->rowCount(); 00263 $res = new ResultWrapper( $this, $r->fetchAll() ); 00264 } 00265 00266 return $res; 00267 } 00268 00272 function freeResult( $res ) { 00273 if ( $res instanceof ResultWrapper ) { 00274 $res->result = null; 00275 } else { 00276 $res = null; 00277 } 00278 } 00279 00284 function fetchObject( $res ) { 00285 if ( $res instanceof ResultWrapper ) { 00286 $r =& $res->result; 00287 } else { 00288 $r =& $res; 00289 } 00290 00291 $cur = current( $r ); 00292 if ( is_array( $cur ) ) { 00293 next( $r ); 00294 $obj = new stdClass; 00295 foreach ( $cur as $k => $v ) { 00296 if ( !is_numeric( $k ) ) { 00297 $obj->$k = $v; 00298 } 00299 } 00300 00301 return $obj; 00302 } 00303 00304 return false; 00305 } 00306 00311 function fetchRow( $res ) { 00312 if ( $res instanceof ResultWrapper ) { 00313 $r =& $res->result; 00314 } else { 00315 $r =& $res; 00316 } 00317 $cur = current( $r ); 00318 if ( is_array( $cur ) ) { 00319 next( $r ); 00320 00321 return $cur; 00322 } 00323 00324 return false; 00325 } 00326 00333 function numRows( $res ) { 00334 $r = $res instanceof ResultWrapper ? $res->result : $res; 00335 00336 return count( $r ); 00337 } 00338 00343 function numFields( $res ) { 00344 $r = $res instanceof ResultWrapper ? $res->result : $res; 00345 00346 return is_array( $r ) ? count( $r[0] ) : 0; 00347 } 00348 00354 function fieldName( $res, $n ) { 00355 $r = $res instanceof ResultWrapper ? $res->result : $res; 00356 if ( is_array( $r ) ) { 00357 $keys = array_keys( $r[0] ); 00358 00359 return $keys[$n]; 00360 } 00361 00362 return false; 00363 } 00364 00372 function tableName( $name, $format = 'quoted' ) { 00373 // table names starting with sqlite_ are reserved 00374 if ( strpos( $name, 'sqlite_' ) === 0 ) { 00375 return $name; 00376 } 00377 00378 return str_replace( '"', '', parent::tableName( $name, $format ) ); 00379 } 00380 00387 function indexName( $index ) { 00388 return $index; 00389 } 00390 00396 function insertId() { 00397 // PDO::lastInsertId yields a string :( 00398 return intval( $this->mConn->lastInsertId() ); 00399 } 00400 00405 function dataSeek( $res, $row ) { 00406 if ( $res instanceof ResultWrapper ) { 00407 $r =& $res->result; 00408 } else { 00409 $r =& $res; 00410 } 00411 reset( $r ); 00412 if ( $row > 0 ) { 00413 for ( $i = 0; $i < $row; $i++ ) { 00414 next( $r ); 00415 } 00416 } 00417 } 00418 00422 function lastError() { 00423 if ( !is_object( $this->mConn ) ) { 00424 return "Cannot return last error, no db connection"; 00425 } 00426 $e = $this->mConn->errorInfo(); 00427 00428 return isset( $e[2] ) ? $e[2] : ''; 00429 } 00430 00434 function lastErrno() { 00435 if ( !is_object( $this->mConn ) ) { 00436 return "Cannot return last error, no db connection"; 00437 } else { 00438 $info = $this->mConn->errorInfo(); 00439 00440 return $info[1]; 00441 } 00442 } 00443 00447 function affectedRows() { 00448 return $this->mAffectedRows; 00449 } 00450 00461 function indexInfo( $table, $index, $fname = __METHOD__ ) { 00462 $sql = 'PRAGMA index_info(' . $this->addQuotes( $this->indexName( $index ) ) . ')'; 00463 $res = $this->query( $sql, $fname ); 00464 if ( !$res ) { 00465 return null; 00466 } 00467 if ( $res->numRows() == 0 ) { 00468 return false; 00469 } 00470 $info = array(); 00471 foreach ( $res as $row ) { 00472 $info[] = $row->name; 00473 } 00474 00475 return $info; 00476 } 00477 00484 function indexUnique( $table, $index, $fname = __METHOD__ ) { 00485 $row = $this->selectRow( 'sqlite_master', '*', 00486 array( 00487 'type' => 'index', 00488 'name' => $this->indexName( $index ), 00489 ), $fname ); 00490 if ( !$row || !isset( $row->sql ) ) { 00491 return null; 00492 } 00493 00494 // $row->sql will be of the form CREATE [UNIQUE] INDEX ... 00495 $indexPos = strpos( $row->sql, 'INDEX' ); 00496 if ( $indexPos === false ) { 00497 return null; 00498 } 00499 $firstPart = substr( $row->sql, 0, $indexPos ); 00500 $options = explode( ' ', $firstPart ); 00501 00502 return in_array( 'UNIQUE', $options ); 00503 } 00504 00511 function makeSelectOptions( $options ) { 00512 foreach ( $options as $k => $v ) { 00513 if ( is_numeric( $k ) && ( $v == 'FOR UPDATE' || $v == 'LOCK IN SHARE MODE' ) ) { 00514 $options[$k] = ''; 00515 } 00516 } 00517 00518 return parent::makeSelectOptions( $options ); 00519 } 00520 00525 protected function makeUpdateOptionsArray( $options ) { 00526 $options = parent::makeUpdateOptionsArray( $options ); 00527 $options = self::fixIgnore( $options ); 00528 00529 return $options; 00530 } 00531 00536 static function fixIgnore( $options ) { 00537 # SQLite uses OR IGNORE not just IGNORE 00538 foreach ( $options as $k => $v ) { 00539 if ( $v == 'IGNORE' ) { 00540 $options[$k] = 'OR IGNORE'; 00541 } 00542 } 00543 00544 return $options; 00545 } 00546 00551 function makeInsertOptions( $options ) { 00552 $options = self::fixIgnore( $options ); 00553 00554 return parent::makeInsertOptions( $options ); 00555 } 00556 00565 function insert( $table, $a, $fname = __METHOD__, $options = array() ) { 00566 if ( !count( $a ) ) { 00567 return true; 00568 } 00569 00570 # SQLite can't handle multi-row inserts, so divide up into multiple single-row inserts 00571 if ( isset( $a[0] ) && is_array( $a[0] ) ) { 00572 $ret = true; 00573 foreach ( $a as $v ) { 00574 if ( !parent::insert( $table, $v, "$fname/multi-row", $options ) ) { 00575 $ret = false; 00576 } 00577 } 00578 } else { 00579 $ret = parent::insert( $table, $a, "$fname/single-row", $options ); 00580 } 00581 00582 return $ret; 00583 } 00584 00592 function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) { 00593 if ( !count( $rows ) ) { 00594 return true; 00595 } 00596 00597 # SQLite can't handle multi-row replaces, so divide up into multiple single-row queries 00598 if ( isset( $rows[0] ) && is_array( $rows[0] ) ) { 00599 $ret = true; 00600 foreach ( $rows as $v ) { 00601 if ( !$this->nativeReplace( $table, $v, "$fname/multi-row" ) ) { 00602 $ret = false; 00603 } 00604 } 00605 } else { 00606 $ret = $this->nativeReplace( $table, $rows, "$fname/single-row" ); 00607 } 00608 00609 return $ret; 00610 } 00611 00620 function textFieldSize( $table, $field ) { 00621 return -1; 00622 } 00623 00627 function unionSupportsOrderAndLimit() { 00628 return false; 00629 } 00630 00636 function unionQueries( $sqls, $all ) { 00637 $glue = $all ? ' UNION ALL ' : ' UNION '; 00638 00639 return implode( $glue, $sqls ); 00640 } 00641 00645 function wasDeadlock() { 00646 return $this->lastErrno() == 5; // SQLITE_BUSY 00647 } 00648 00652 function wasErrorReissuable() { 00653 return $this->lastErrno() == 17; // SQLITE_SCHEMA; 00654 } 00655 00659 function wasReadOnlyError() { 00660 return $this->lastErrno() == 8; // SQLITE_READONLY; 00661 } 00662 00666 public function getSoftwareLink() { 00667 return "[{{int:version-db-sqlite-url}} SQLite]"; 00668 } 00669 00673 function getServerVersion() { 00674 $ver = $this->mConn->getAttribute( PDO::ATTR_SERVER_VERSION ); 00675 00676 return $ver; 00677 } 00678 00682 public function getServerInfo() { 00683 return wfMessage( self::getFulltextSearchModule() 00684 ? 'sqlite-has-fts' 00685 : 'sqlite-no-fts', $this->getServerVersion() )->text(); 00686 } 00687 00696 function fieldInfo( $table, $field ) { 00697 $tableName = $this->tableName( $table ); 00698 $sql = 'PRAGMA table_info(' . $this->addQuotes( $tableName ) . ')'; 00699 $res = $this->query( $sql, __METHOD__ ); 00700 foreach ( $res as $row ) { 00701 if ( $row->name == $field ) { 00702 return new SQLiteField( $row, $tableName ); 00703 } 00704 } 00705 00706 return false; 00707 } 00708 00709 protected function doBegin( $fname = '' ) { 00710 if ( $this->mTrxLevel == 1 ) { 00711 $this->commit( __METHOD__ ); 00712 } 00713 try { 00714 $this->mConn->beginTransaction(); 00715 } catch ( PDOException $e ) { 00716 throw new DBUnexpectedError( $this, 'Error in BEGIN query: ' . $e->getMessage() ); 00717 } 00718 $this->mTrxLevel = 1; 00719 } 00720 00721 protected function doCommit( $fname = '' ) { 00722 if ( $this->mTrxLevel == 0 ) { 00723 return; 00724 } 00725 try { 00726 $this->mConn->commit(); 00727 } catch ( PDOException $e ) { 00728 throw new DBUnexpectedError( $this, 'Error in COMMIT query: ' . $e->getMessage() ); 00729 } 00730 $this->mTrxLevel = 0; 00731 } 00732 00733 protected function doRollback( $fname = '' ) { 00734 if ( $this->mTrxLevel == 0 ) { 00735 return; 00736 } 00737 $this->mConn->rollBack(); 00738 $this->mTrxLevel = 0; 00739 } 00740 00745 function strencode( $s ) { 00746 return substr( $this->addQuotes( $s ), 1, -1 ); 00747 } 00748 00753 function encodeBlob( $b ) { 00754 return new Blob( $b ); 00755 } 00756 00761 function decodeBlob( $b ) { 00762 if ( $b instanceof Blob ) { 00763 $b = $b->fetch(); 00764 } 00765 00766 return $b; 00767 } 00768 00773 function addQuotes( $s ) { 00774 if ( $s instanceof Blob ) { 00775 return "x'" . bin2hex( $s->fetch() ) . "'"; 00776 } elseif ( is_bool( $s ) ) { 00777 return (int)$s; 00778 } elseif ( strpos( $s, "\0" ) !== false ) { 00779 // SQLite doesn't support \0 in strings, so use the hex representation as a workaround. 00780 // This is a known limitation of SQLite's mprintf function which PDO should work around, 00781 // but doesn't. I have reported this to php.net as bug #63419: 00782 // https://bugs.php.net/bug.php?id=63419 00783 // There was already a similar report for SQLite3::escapeString, bug #62361: 00784 // https://bugs.php.net/bug.php?id=62361 00785 return "x'" . bin2hex( $s ) . "'"; 00786 } else { 00787 return $this->mConn->quote( $s ); 00788 } 00789 } 00790 00794 function buildLike() { 00795 $params = func_get_args(); 00796 if ( count( $params ) > 0 && is_array( $params[0] ) ) { 00797 $params = $params[0]; 00798 } 00799 00800 return parent::buildLike( $params ) . "ESCAPE '\' "; 00801 } 00802 00806 public function getSearchEngine() { 00807 return "SearchSqlite"; 00808 } 00809 00815 public function deadlockLoop( /*...*/ ) { 00816 $args = func_get_args(); 00817 $function = array_shift( $args ); 00818 00819 return call_user_func_array( $function, $args ); 00820 } 00821 00826 protected function replaceVars( $s ) { 00827 $s = parent::replaceVars( $s ); 00828 if ( preg_match( '/^\s*(CREATE|ALTER) TABLE/i', $s ) ) { 00829 // CREATE TABLE hacks to allow schema file sharing with MySQL 00830 00831 // binary/varbinary column type -> blob 00832 $s = preg_replace( '/\b(var)?binary(\(\d+\))/i', 'BLOB', $s ); 00833 // no such thing as unsigned 00834 $s = preg_replace( '/\b(un)?signed\b/i', '', $s ); 00835 // INT -> INTEGER 00836 $s = preg_replace( '/\b(tiny|small|medium|big|)int(\s*\(\s*\d+\s*\)|\b)/i', 'INTEGER', $s ); 00837 // floating point types -> REAL 00838 $s = preg_replace( 00839 '/\b(float|double(\s+precision)?)(\s*\(\s*\d+\s*(,\s*\d+\s*)?\)|\b)/i', 00840 'REAL', 00841 $s 00842 ); 00843 // varchar -> TEXT 00844 $s = preg_replace( '/\b(var)?char\s*\(.*?\)/i', 'TEXT', $s ); 00845 // TEXT normalization 00846 $s = preg_replace( '/\b(tiny|medium|long)text\b/i', 'TEXT', $s ); 00847 // BLOB normalization 00848 $s = preg_replace( '/\b(tiny|small|medium|long|)blob\b/i', 'BLOB', $s ); 00849 // BOOL -> INTEGER 00850 $s = preg_replace( '/\bbool(ean)?\b/i', 'INTEGER', $s ); 00851 // DATETIME -> TEXT 00852 $s = preg_replace( '/\b(datetime|timestamp)\b/i', 'TEXT', $s ); 00853 // No ENUM type 00854 $s = preg_replace( '/\benum\s*\([^)]*\)/i', 'TEXT', $s ); 00855 // binary collation type -> nothing 00856 $s = preg_replace( '/\bbinary\b/i', '', $s ); 00857 // auto_increment -> autoincrement 00858 $s = preg_replace( '/\bauto_increment\b/i', 'AUTOINCREMENT', $s ); 00859 // No explicit options 00860 $s = preg_replace( '/\)[^);]*(;?)\s*$/', ')\1', $s ); 00861 // AUTOINCREMENT should immedidately follow PRIMARY KEY 00862 $s = preg_replace( '/primary key (.*?) autoincrement/i', 'PRIMARY KEY AUTOINCREMENT $1', $s ); 00863 } elseif ( preg_match( '/^\s*CREATE (\s*(?:UNIQUE|FULLTEXT)\s+)?INDEX/i', $s ) ) { 00864 // No truncated indexes 00865 $s = preg_replace( '/\(\d+\)/', '', $s ); 00866 // No FULLTEXT 00867 $s = preg_replace( '/\bfulltext\b/i', '', $s ); 00868 } elseif ( preg_match( '/^\s*DROP INDEX/i', $s ) ) { 00869 // DROP INDEX is database-wide, not table-specific, so no ON <table> clause. 00870 $s = preg_replace( '/\sON\s+[^\s]*/i', '', $s ); 00871 } 00872 00873 return $s; 00874 } 00875 00876 public function lock( $lockName, $method, $timeout = 5 ) { 00877 global $wgSQLiteDataDir; 00878 00879 if ( !is_dir( "$wgSQLiteDataDir/locks" ) ) { // create dir as needed 00880 if ( !is_writable( $wgSQLiteDataDir ) || !mkdir( "$wgSQLiteDataDir/locks" ) ) { 00881 throw new DBError( "Cannot create directory \"$wgSQLiteDataDir/locks\"." ); 00882 } 00883 } 00884 00885 return $this->lockMgr->lock( array( $lockName ), LockManager::LOCK_EX, $timeout )->isOK(); 00886 } 00887 00888 public function unlock( $lockName, $method ) { 00889 return $this->lockMgr->unlock( array( $lockName ), LockManager::LOCK_EX )->isOK(); 00890 } 00891 00898 function buildConcat( $stringList ) { 00899 return '(' . implode( ') || (', $stringList ) . ')'; 00900 } 00901 00902 public function buildGroupConcatField( 00903 $delim, $table, $field, $conds = '', $join_conds = array() 00904 ) { 00905 $fld = "group_concat($field," . $this->addQuotes( $delim ) . ')'; 00906 00907 return '(' . $this->selectSQLText( $table, $fld, $conds, null, array(), $join_conds ) . ')'; 00908 } 00909 00918 function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = __METHOD__ ) { 00919 $res = $this->query( "SELECT sql FROM sqlite_master WHERE tbl_name=" . 00920 $this->addQuotes( $oldName ) . " AND type='table'", $fname ); 00921 $obj = $this->fetchObject( $res ); 00922 if ( !$obj ) { 00923 throw new MWException( "Couldn't retrieve structure for table $oldName" ); 00924 } 00925 $sql = $obj->sql; 00926 $sql = preg_replace( 00927 '/(?<=\W)"?' . preg_quote( trim( $this->addIdentifierQuotes( $oldName ), '"' ) ) . '"?(?=\W)/', 00928 $this->addIdentifierQuotes( $newName ), 00929 $sql, 00930 1 00931 ); 00932 if ( $temporary ) { 00933 if ( preg_match( '/^\\s*CREATE\\s+VIRTUAL\\s+TABLE\b/i', $sql ) ) { 00934 wfDebug( "Table $oldName is virtual, can't create a temporary duplicate.\n" ); 00935 } else { 00936 $sql = str_replace( 'CREATE TABLE', 'CREATE TEMPORARY TABLE', $sql ); 00937 } 00938 } 00939 00940 return $this->query( $sql, $fname ); 00941 } 00942 00951 function listTables( $prefix = null, $fname = __METHOD__ ) { 00952 $result = $this->select( 00953 'sqlite_master', 00954 'name', 00955 "type='table'" 00956 ); 00957 00958 $endArray = array(); 00959 00960 foreach ( $result as $table ) { 00961 $vars = get_object_vars( $table ); 00962 $table = array_pop( $vars ); 00963 00964 if ( !$prefix || strpos( $table, $prefix ) === 0 ) { 00965 if ( strpos( $table, 'sqlite_' ) !== 0 ) { 00966 $endArray[] = $table; 00967 } 00968 } 00969 } 00970 00971 return $endArray; 00972 } 00973 } // end DatabaseSqlite class 00974 00979 class DatabaseSqliteStandalone extends DatabaseSqlite { 00980 public function __construct( $fileName, $flags = 0 ) { 00981 $this->mFlags = $flags; 00982 $this->tablePrefix( null ); 00983 $this->openFile( $fileName ); 00984 } 00985 } 00986 00990 class SQLiteField implements Field { 00991 private $info, $tableName; 00992 00993 function __construct( $info, $tableName ) { 00994 $this->info = $info; 00995 $this->tableName = $tableName; 00996 } 00997 00998 function name() { 00999 return $this->info->name; 01000 } 01001 01002 function tableName() { 01003 return $this->tableName; 01004 } 01005 01006 function defaultValue() { 01007 if ( is_string( $this->info->dflt_value ) ) { 01008 // Typically quoted 01009 if ( preg_match( '/^\'(.*)\'$', $this->info->dflt_value ) ) { 01010 return str_replace( "''", "'", $this->info->dflt_value ); 01011 } 01012 } 01013 01014 return $this->info->dflt_value; 01015 } 01016 01020 function isNullable() { 01021 return !$this->info->notnull; 01022 } 01023 01024 function type() { 01025 return $this->info->type; 01026 } 01027 } // end SQLiteField