DB2: New LIST_SET_PREPARED mode for DatabaseIbm_db2::makeList() that handles ? tokens in prepared UPDATE statement
DB2: General fixes for DB2 database schema
DB2: Factored out foreign key definitions into foreignkeys.sql so that more can be added down the line without messing with the main schema
DB2: Better limit and offset support
define( 'LIST_SET', 2 );
define( 'LIST_NAMES', 3);
define( 'LIST_OR', 4);
+define( 'LIST_SET_PREPARED', 8); // List of (?, ?, ?) for DatabaseIbm_db2
/**
* Unicode and normalisation related
# TS_POSTGRES
} elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d* GMT$/', $ts, $da ) ) {
# TS_POSTGRES
+ } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.\d\d\d$/',$ts,$da)) {
+ # TS_DB2
} elseif ( preg_match( '/^[A-Z][a-z]{2}, \d\d [A-Z][a-z]{2} \d{4} \d\d:\d\d:\d\d/', $ts ) ) {
# TS_RFC2822
$uts = strtotime( $ts );
* @param $string String: the relevant debug message
*/
private function installPrint($string) {
- wfDebug("$string");
+ wfDebug("$string\n");
if ($this->mMode == self::INSTALL_MODE) {
print "<li>$string</li>";
flush();
*/
/*private*/
public function doQuery( $sql ) {
- //print "<li><pre>$sql</pre></li>";
- // Switch into the correct namespace
$this->applySchema();
$ret = db2_exec( $this->mConn, $sql, $this->mStmtOptions );
- if( !$ret ) {
- print "<br><pre>";
- print $sql;
- print "</pre><br>";
+ if( $ret == FALSE ) {
$error = db2_stmt_errormsg();
+ $this->installPrint("<pre>$sql</pre>");
+ $this->installPrint($error);
throw new DBUnexpectedError($this, 'SQL error: ' . htmlspecialchars( $error ) );
}
$this->mLastResult = $ret;
} else {
print " done</li>";
}
+ $res = $this->sourceFile( "../maintenance/ibm_db2/foreignkeys.sql" );
+ if ($res !== true) {
+ print " <b>FAILED</b>: " . htmlspecialchars( $res ) . "</li>";
+ } else {
+ print "<li>Foreign keys done</li>";
+ }
$res = null;
// TODO: populate interwiki links
* LIST_OR - ORed WHERE clause (without the WHERE)
* LIST_SET - comma separated with field names, like a SET clause
* LIST_NAMES - comma separated field names
+ * LIST_SET_PREPARED - like LIST_SET, except with ? tokens as values
*/
- public function makeList( $a, $mode = LIST_COMMA ) {
+ function makeList( $a, $mode = LIST_COMMA ) {
if ( !is_array( $a ) ) {
- throw new DBUnexpectedError( $this, 'Database::makeList called with incorrect parameters' );
+ throw new DBUnexpectedError( $this, 'DatabaseBase::makeList called with incorrect parameters' );
}
-
- $first = true;
- $list = '';
- foreach ( $a as $field => $value ) {
- if ( !$first ) {
- if ( $mode == LIST_AND ) {
- $list .= ' AND ';
- } elseif($mode == LIST_OR) {
- $list .= ' OR ';
- } else {
- $list .= ',';
- }
- } else {
- $first = false;
- }
- if ( ($mode == LIST_AND || $mode == LIST_OR) && is_numeric( $field ) ) {
- $list .= "($value)";
- } elseif ( ($mode == LIST_SET) && is_numeric( $field ) ) {
- $list .= "$value";
- } elseif ( ($mode == LIST_AND || $mode == LIST_OR) && is_array($value) ) {
- if( count( $value ) == 0 ) {
- throw new MWException( __METHOD__.': empty input' );
- } elseif( count( $value ) == 1 ) {
- // Special-case single values, as IN isn't terribly efficient
- // Don't necessarily assume the single key is 0; we don't
- // enforce linear numeric ordering on other arrays here.
- $value = array_values( $value );
- $list .= $field." = ".$this->addQuotes( $value[0] );
- } else {
- $list .= $field." IN (".$this->makeList($value).") ";
- }
- } elseif( is_null($value) ) {
- if ( $mode == LIST_AND || $mode == LIST_OR ) {
- $list .= "$field IS ";
- } elseif ( $mode == LIST_SET ) {
- $list .= "$field = ";
- }
- $list .= 'NULL';
- } else {
- if ( $mode == LIST_AND || $mode == LIST_OR || $mode == LIST_SET ) {
- $list .= "$field = ";
- }
- if ( $mode == LIST_NAMES ) {
- $list .= $value;
- }
- // Leo: Can't insert quoted numbers into numeric columns
- // (?) Might cause other problems. May have to check column type before insertion.
- else if ( is_numeric($value) ) {
- $list .= $value;
+
+ // if this is for a prepared UPDATE statement
+ // (this should be promoted to the parent class
+ // once other databases use prepared statements)
+ if ($mode == LIST_SET_PREPARED) {
+ $first = true;
+ $list = '';
+ foreach ( $a as $field => $value ) {
+ if (!$first) {
+ $list .= ", $field = ?";
}
else {
- $list .= $this->addQuotes( $value );
+ $list .= "( $field = ?";
+ $first = false;
}
}
+ $list .= ')';
+
+ return $list;
}
- return $list;
+
+ // otherwise, call the usual function
+ return parent::makeList( $a, $mode );
}
/**
throw new DBUnexpectedError( $this, "Invalid non-numeric limit passed to limitResult()\n" );
}
if( $offset ) {
- $this->installPrint("Offset parameter not supported in limitResult()\n");
+ //$this->installPrint("Offset parameter not supported in limitResult()\n");
+ if ( stripos($sql, 'where') === false ) {
+ return "$sql AND (ROWNUM BETWEEN $offset AND $offset+$limit)";
+ }
+ else {
+ return "$sql WHERE (ROWNUM BETWEEN $offset AND $offset+$limit)";
+ }
}
- // TODO implement proper offset handling
- // idea: get all the rows between 0 and offset, advance cursor to offset
return "$sql FETCH FIRST $limit ROWS ONLY ";
}
*/
private function calcInsertId($table, $primaryKey, $stmt) {
if ($primaryKey) {
- $id_row = $this->fetchRow($stmt);
- $this->mInsertId = $id_row[0];
+ $this->mInsertId = db2_last_insert_id($this->mConn);
+ //$this->installPrint("Last $primaryKey for $table was $this->mInsertId");
}
}
// get database-specific table name (not used)
$table = $this->tableName( $table );
// format options as an array
- if ( !is_array( $options ) ) $options = array( $options );
+ $options = IBM_DB2Helper::makeArray($options);
// format args as an array of arrays
if ( !( isset( $args[0] ) && is_array( $args[0] ) ) ) {
$args = array($args);
}
+
// prevent insertion of NULL into primary key columns
list($args, $primaryKeys) = $this->removeNullPrimaryKeys($table, $args);
// if there's only one primary key
}
$sql = "INSERT INTO $table (" . implode( ',', $keys ) . ') VALUES ';
- switch($key_count) {
- //case 0 impossible
- case 1:
- $sql .= '(?)';
- break;
- default:
- $sql .= '(?' . str_repeat(',?', $key_count-1) . ')';
- }
- // add logic to read back the new primary key value
- if ($primaryKey) {
- $sql = "SELECT $primaryKey FROM FINAL TABLE($sql)";
+ if ($key_count == 1) {
+ $sql .= '(?)';
+ } else {
+ $sql .= '(?' . str_repeat(',?', $key_count-1) . ')';
}
+ //$this->installPrint("Preparing the following SQL:");
+ //$this->installPrint("$sql");
+ //$this->installPrint(print_r($args, true));
$stmt = $this->prepare($sql);
// start a transaction/enter transaction mode
$this->begin();
if ( !$ignore ) {
+ //$first = true;
foreach ( $args as $row ) {
+ //$this->installPrint("Inserting " . print_r($row, true));
// insert each row into the database
$res = $res & $this->execute($stmt, $row);
+ if (!$res) {
+ $this->installPrint("Last error:");
+ $this->installPrint($this->lastError());
+ }
// get the last inserted value into a generated column
$this->calcInsertId($table, $primaryKey, $stmt);
}
foreach ( $args as $row ) {
$overhead = "SAVEPOINT $ignore ON ROLLBACK RETAIN CURSORS";
db2_exec($this->mConn, $overhead, $this->mStmtOptions);
+ //$this->installPrint("Inserting " . print_r($row, true));
$this->execute($stmt, $row);
+ //$this->installPrint(wfGetAllCallers());
+ if (!$res2) {
+ $this->installPrint("Last error:");
+ $this->installPrint($this->lastError());
+ }
// get the last inserted value into a generated column
$this->calcInsertId($table, $primaryKey, $stmt);
}
// commit either way
$this->commit();
+ $this->freePrepared($stmt);
return $res;
}
public function update( $table, $values, $conds, $fname = 'Database::update', $options = array() ) {
$table = $this->tableName( $table );
$opts = $this->makeUpdateOptions( $options );
- $sql = "UPDATE $opts $table SET " . $this->makeList( $values, LIST_SET );
+ $sql = "UPDATE $opts $table SET " . $this->makeList( $values, LIST_SET_PREPARED );
if ( $conds != '*' ) {
$sql .= " WHERE " . $this->makeList( $conds, LIST_AND );
}
- return $this->query( $sql, $fname );
+ $stmt = $this->prepare( $sql );
+ $this->installPrint("UPDATE: " . print_r($values, TRUE));
+ // assuming for now that an array with string keys will work
+ // if not, convert to simple array first
+ $result = $this->execute( $stmt, $values );
+ $this->freePrepared( $stmt );
+ //$result = $this->query( $sql, $fname );
+ // commit regardless of state
+ //$this->commit();
+ return $result;
}
/**
if ( $conds != '*' ) {
$sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
}
- return $this->query( $sql, $fname );
+ $result = $this->query( $sql, $fname );
+ // commit regardless
+ //$this->commit();
+ return $result;
}
/**
* @return mixed
*/
public function decodeBlob($b) {
- return $b->getData();
+ return "$b";
}
/**
return 'BITOR('.$fieldLeft.', '.$fieldRight.')';
}
}
+
+class IBM_DB2Helper {
+ public static function makeArray($maybeArray) {
+ if ( !is_array( $maybeArray ) ) $maybeArray = array( $maybeArray );
+
+ return $maybeArray;
+ }
+}
--- /dev/null
+-- good\r
+ALTER TABLE user_groups ADD CONSTRAINT USER_GROUPS_FK1 FOREIGN KEY (ug_user) REFERENCES user(user_id) ON DELETE CASCADE\r
+;\r
+\r
+-- good\r
+ALTER TABLE user_newtalk ADD CONSTRAINT USER_NEWTALK_FK1 FOREIGN KEY (user_id) REFERENCES user(user_id) ON DELETE CASCADE\r
+;\r
+\r
+-- referenced value not found\r
+ALTER TABLE revision ADD CONSTRAINT REVISION_PAGE_FK FOREIGN KEY (rev_page) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+-- referenced value not found\r
+ALTER TABLE revision ADD CONSTRAINT REVISION_USER_FK FOREIGN KEY (rev_user) REFERENCES user(user_id) ON DELETE RESTRICT\r
+;\r
+\r
+-- good\r
+ALTER TABLE page_restrictions ADD CONSTRAINT PAGE_RESTRICTIONS_PAGE_FK FOREIGN KEY (pr_page) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- good\r
+ALTER TABLE page_props ADD CONSTRAINT PAGE_PROPS_PAGE_FK FOREIGN KEY (pp_page) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE archive ADD CONSTRAINT ARCHIVE_USER_FK FOREIGN KEY (ar_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- referenced value not found\r
+ALTER TABLE redirect ADD CONSTRAINT REDIRECT_FROM_FK FOREIGN KEY (rd_from) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- referenced value not found\r
+ALTER TABLE pagelinks ADD CONSTRAINT PAGELINKS_FROM_FK FOREIGN KEY (pl_from) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- good\r
+ALTER TABLE templatelinks ADD CONSTRAINT TEMPLATELINKS_FROM_FK FOREIGN KEY (tl_from) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- good\r
+ALTER TABLE imagelinks ADD CONSTRAINT IMAGELINKS_FROM_FK FOREIGN KEY (il_from) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- good\r
+ALTER TABLE categorylinks ADD CONSTRAINT CATEGORYLINKS_FROM_FK FOREIGN KEY (cl_from) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- good\r
+ALTER TABLE externallinks ADD CONSTRAINT EXTERNALLINKS_FROM_FK FOREIGN KEY (el_from) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- good\r
+ALTER TABLE langlinks ADD CONSTRAINT LANGLINKS_FROM_FK FOREIGN KEY (ll_from) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE ipblocks ADD CONSTRAINT IPBLOCKS_USER_FK FOREIGN KEY (ipb_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- good\r
+ALTER TABLE ipblocks ADD CONSTRAINT IPBLOCKS_BY_FK FOREIGN KEY (ipb_by) REFERENCES user(user_id) ON DELETE CASCADE\r
+;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE image ADD CONSTRAINT IMAGE_USER_FK FOREIGN KEY (img_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE oldimage ADD CONSTRAINT OLDIMAGE_USER_FK FOREIGN KEY (oi_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- good\r
+ALTER TABLE oldimage ADD CONSTRAINT OLDIMAGE_NAME_FK FOREIGN KEY (oi_name) REFERENCES image(img_name) ON DELETE CASCADE\r
+;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE filearchive ADD CONSTRAINT FILEARCHIVE_DELETED_USER_FK FOREIGN KEY (fa_deleted_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE filearchive ADD CONSTRAINT FILEARCHIVE_USER_FK FOREIGN KEY (fa_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE recentchanges ADD CONSTRAINT RECENTCHANGES_USER_FK FOREIGN KEY (rc_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE recentchanges ADD CONSTRAINT RECENTCHANGES_CUR_ID_FK FOREIGN KEY (rc_cur_id) REFERENCES page(page_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- good\r
+ALTER TABLE watchlist ADD CONSTRAINT WATCHLIST_USER_FK FOREIGN KEY (wl_user) REFERENCES user(user_id) ON DELETE CASCADE\r
+;\r
+\r
+-- good\r
+-- already in MySQL schema\r
+ALTER TABLE trackbacks ADD CONSTRAINT TRACKBACKS_PAGE_FK FOREIGN KEY (tb_page) REFERENCES page(page_id) ON DELETE CASCADE\r
+;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE protected_titles ADD CONSTRAINT PROTECTED_TITLES_USER_FK FOREIGN KEY (pt_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;\r
+\r
+-- cannot contain null values\r
+-- ALTER TABLE logging ADD CONSTRAINT LOGGING_USER_FK FOREIGN KEY (log_user) REFERENCES user(user_id) ON DELETE SET NULL\r
+--;
\ No newline at end of file
CREATE TABLE user (
+ -- Needs to start with 0
user_id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
user_name VARCHAR(255) NOT NULL UNIQUE,
user_real_name VARCHAR(255),
CREATE TABLE page (
- page_id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
+ page_id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
page_namespace SMALLINT NOT NULL,
page_title VARCHAR(255) NOT NULL,
page_restrictions VARCHAR(1024),
CREATE TABLE revision (
- rev_id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
+ rev_id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
rev_page BIGINT NOT NULL DEFAULT 0,
-- REFERENCES page (page_id) ON DELETE CASCADE,
rev_text_id BIGINT, -- FK
CREATE TABLE text ( -- replaces reserved word 'text'
- --old_id INTEGER NOT NULL,
- old_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
- --PRIMARY KEY DEFAULT nextval('text_old_id_val'),
+ old_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
old_text CLOB(16M) INLINE LENGTH 4096,
old_flags VARCHAR(1024)
);
CREATE TABLE page_restrictions (
--pr_id INTEGER NOT NULL UNIQUE, --DEFAULT nextval('pr_id_val'),
- --pr_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
- pr_id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0),
+ --pr_id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
+ pr_id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
pr_page INTEGER NOT NULL DEFAULT 0,
--(used to be nullable)
-- REFERENCES page (page_id) ON DELETE CASCADE,
CREATE TABLE redirect (
- rd_from BIGINT NOT NULL PRIMARY KEY,
+ rd_from BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
--REFERENCES page(page_id) ON DELETE CASCADE,
rd_namespace SMALLINT NOT NULL DEFAULT 0,
rd_title VARCHAR(255) NOT NULL DEFAULT '',
--
CREATE TABLE external_user (
-- Foreign key to user_id
- eu_local_id BIGINT NOT NULL PRIMARY KEY,
+ eu_local_id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
-- Some opaque identifier provided by the external database
eu_external_id VARCHAR(255) NOT NULL
);
CREATE TABLE ipblocks (
- ipb_id INTEGER NOT NULL PRIMARY KEY,
+ ipb_id INTEGER NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
--DEFAULT nextval('ipblocks_ipb_id_val'),
ipb_address VARCHAR(1024),
ipb_user BIGINT NOT NULL DEFAULT 0,
oi_sha1 VARCHAR(255) NOT NULL DEFAULT ''
--FOREIGN KEY (oi_name) REFERENCES image(img_name) ON DELETE CASCADE
);
---ALTER TABLE oldimage ADD CONSTRAINT oldimage_oi_name_fkey_cascade FOREIGN KEY (oi_name) REFERENCES image(img_name) ON DELETE CASCADE;
CREATE INDEX oi_name_timestamp ON oldimage (oi_name,oi_timestamp);
CREATE INDEX oi_name_archive_name ON oldimage (oi_name,oi_archive_name);
CREATE INDEX oi_sha1 ON oldimage (oi_sha1);
CREATE TABLE filearchive (
- fa_id INTEGER NOT NULL PRIMARY KEY,
+ fa_id INTEGER NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
--PRIMARY KEY DEFAULT nextval('filearchive_fa_id_seq'),
fa_name VARCHAR(255) NOT NULL,
fa_archive_name VARCHAR(255),
CREATE TABLE recentchanges (
- rc_id INTEGER NOT NULL PRIMARY KEY,
+ rc_id INTEGER NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
--PRIMARY KEY DEFAULT nextval('rc_rc_id_seq'),
rc_timestamp TIMESTAMP(3) NOT NULL,
rc_cur_time TIMESTAMP(3) NOT NULL,
CREATE TABLE logging (
- log_id BIGINT NOT NULL PRIMARY KEY,
+ log_id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
--PRIMARY KEY DEFAULT nextval('log_log_id_seq'),
log_type VARCHAR(32) NOT NULL,
log_action VARCHAR(32) NOT NULL,
CREATE TABLE trackbacks (
- tb_id INTEGER NOT NULL PRIMARY KEY,
+ tb_id INTEGER NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
--PRIMARY KEY DEFAULT nextval('trackbacks_tb_id_seq'),
-- foreign key also in MySQL
- tb_page INTEGER REFERENCES page(page_id) ON DELETE CASCADE,
+ tb_page INTEGER,
+ -- REFERENCES page(page_id) ON DELETE CASCADE,
tb_title VARCHAR(255) NOT NULL,
tb_url CLOB(64K) INLINE LENGTH 4096 NOT NULL,
tb_ex CLOB(64K) INLINE LENGTH 4096,
CREATE TABLE job (
- job_id BIGINT NOT NULL PRIMARY KEY,
+ job_id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
--PRIMARY KEY DEFAULT nextval('job_job_id_seq'),
job_cmd VARCHAR(255) NOT NULL,
job_namespace SMALLINT NOT NULL,
CREATE INDEX job_cmd_namespace_title ON job (job_cmd, job_namespace, job_title);
-
--- Postgres' Tsearch2 dropped
---ALTER TABLE page ADD titlevector tsvector;
---CREATE FUNCTION ts2_page_title() RETURNS TRIGGER LANGUAGE plpgsql AS
---$mw$
---BEGIN
---IF TG_OP = 'INSERT' THEN
--- NEW.titlevector = to_tsvector('default',REPLACE(NEW.page_title,'/',' '));
---ELSIF NEW.page_title != OLD.page_title THEN
--- NEW.titlevector := to_tsvector('default',REPLACE(NEW.page_title,'/',' '));
---END IF;
---RETURN NEW;
---END;
---$mw$;
-
---CREATE TRIGGER ts2_page_title BEFORE INSERT OR UPDATE ON page
--- FOR EACH ROW EXECUTE PROCEDURE ts2_page_title();
-
-
---ALTER TABLE text ADD textvector tsvector;
---CREATE FUNCTION ts2_page_text() RETURNS TRIGGER LANGUAGE plpgsql AS
---$mw$
---BEGIN
---IF TG_OP = 'INSERT' THEN
--- NEW.textvector = to_tsvector('default',NEW.old_text);
---ELSIF NEW.old_text != OLD.old_text THEN
--- NEW.textvector := to_tsvector('default',NEW.old_text);
---END IF;
---RETURN NEW;
---END;
---$mw$;
-
---CREATE TRIGGER ts2_page_text BEFORE INSERT OR UPDATE ON text
--- FOR EACH ROW EXECUTE PROCEDURE ts2_page_text();
-
--- These are added by the setup script due to version compatibility issues
--- If using 8.1, we switch from "gin" to "gist"
-
---CREATE INDEX ts2_page_title ON page USING gin(titlevector);
---CREATE INDEX ts2_page_text ON text USING gin(textvector);
-
--TODO
--CREATE FUNCTION add_interwiki (TEXT,INT,SMALLINT) RETURNS INT LANGUAGE SQL AS
--$mw$
CREATE TABLE category (
- cat_id INTEGER NOT NULL PRIMARY KEY,
+ cat_id INTEGER NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1),
--PRIMARY KEY DEFAULT nextval('category_id_seq'),
cat_title VARCHAR(255) NOT NULL,
cat_pages INTEGER NOT NULL DEFAULT 0,