Roxen.git / server / config_interface / dbs / browser.pike

version» Context lines:

Roxen.git/server/config_interface/dbs/browser.pike:1:   #include <config_interface.h>   #include <config.h>   #include <roxen.h>   //<locale-token project="roxen_config">_</locale-token>   #define _(X,Y) _STR_LOCALE("roxen_config",X,Y)      mapping actions = ([    // name title function must be internal -  "move": ({ _(401,"Copy or rename database"),move_db, 0 }), +  "configure_ext_db_con": ({ _(1145,"Configure database connection"), +  configure_ext_db_con, 0 }),    "delete": ({ _(402,"Delete this database"), delete_db, 0 }),    "group": ({ _(324,"Change group for this database"), change_group, 0 }),    "clear": ({ _(403,"Delete all tables"), clear_db, 0 }),    "backup": ({ _(404,"Make a backup"), backup_db, 1 }),    "charset":({ _(536, "Change default character set"), change_charset, 0 }),    "repair": ({ _(537, "Repair all tables"), repair_db, 0 }),    "optimize":({ _(538, "Optimize all tables"), optimize_db, 0 }), -  +  "schedule":({ _(1109, "Change backup schedule"), change_schedule, 2 }),   ]);         #define CU_AUTH id->misc->config_user->auth    -  + // Size limit for single field and aggregated fields (per column) + #define MAX_FIELD_FORMATTED_SIZE (32 * 1024) // 32 K + #define MAX_TOTAL_FORMATTED_SIZE (1024 * 1024) // 1 MB +  +    #define VERIFY(X) do { \    if( !id->variables["yes.x"] ) \    { \    return \    ("<table><tr><td colspan='2'>\n"+ \    sprintf((string)(X), db)+ \    "</td><tr><td><input type=hidden name=action value='&form.action;' />"\    "<submit-gbutton2 name='yes' align='center' " \    " width='&usr.gbutton-width;'>"+_(0,"Yes")+ \    "</submit-gbutton2></td>\n" \ -  "<td align=right><cf-no href="+Roxen.html_encode_string(id->not_query)+\ -  "?db="+Roxen.html_encode_string(id->variables->db)+"/>"+ \ +  "<td align=right><cf-no href='"+Roxen.html_encode_string(id->not_query)+\ +  "?db="+Roxen.html_encode_string(id->variables->db)+ \ +  "&amp;&usr.set-wiz-id;' />"+ \    "</td>\n</table>\n"); \    } \   } while(0)         mixed change_group( string db, RequestID id )   {    if( !id->variables->group )    {    string res ="<br /><blockquote>"
Roxen.git/server/config_interface/dbs/browser.pike:72:    "<b>"+_(541,"New default character set")+":</b> "    "<input type='string' name='default_charset' value='" +    Roxen.html_encode_string(old_charset||"") +"' />";    return res + "</select><submit-gbutton2 name='ok'>"+(201,"OK")+    "</submit-gbutton2>";    }    DBManager.set_db_default_charset( db, id->variables->default_charset );    return 0;   }    + mixed change_schedule( string db, RequestID id ) + { +  Sql.Sql sql = connect_to_my_mysql(0, "roxen"); +  if( !id->variables->backup_schedule ) +  { +  string old_schedule, old_schedule_id; +  array q = sql->query("SELECT schedule_id, schedule FROM dbs, db_schedules " +  " WHERE db_schedules.id = dbs.schedule_id " +  " AND dbs.name = %s", db); +  if (sizeof(q)) { +  old_schedule = q[0]->schedule; +  old_schedule_id = q[0]->schedule_id; +  } +  string res ="<br /><blockquote>" +  "<input type=hidden name=action value='&form.action;' />" +  "<h2>"+sprintf(_(1110,"Changing backup schedule for %s"), db )+ +  "</h2>"+ +  (old_schedule?("<b>"+_(1111, "Old backup schedule")+":</b> " + +  Roxen.html_encode_string(old_schedule)+"<br />"):"")+ +  "<b>"+_(1112,"New backup schedule")+":</b> " +  "<default name='backup_schedule' value='" + old_schedule_id + "'>" +  "<select name='backup_schedule'>"; +  foreach(sql->query("SELECT schedule, id FROM db_schedules " +  " ORDER BY schedule"), mapping(string:string) schedule) { +  res += sprintf("<option value='%s'>%s</option>", +  schedule->id, +  Roxen.html_encode_string(schedule->schedule)); +  } +  res += sprintf("<option value='0'>%s</option>", +  Roxen.html_encode_string(_(1113, "None"))) + +  "</select></default>"; +  return res + "<submit-gbutton2 name='ok'>"+(201,"OK")+ +  "</submit-gbutton2>"; +  } +  if (id->variables->backup_schedule == "0") { +  sql->query("UPDATE dbs SET schedule_id = NULL " +  " WHERE name = %s", db); +  } else { +  sql->query("UPDATE dbs SET schedule_id = %d " +  " WHERE name = %s", (int)id->variables->backup_schedule, db); +  } +  return 0; + } +    mixed repair_db( string db, RequestID id )   {    // CSS stylesheet    string res = "<style type='text/css'>"    "#tbl {"    " font-size: smaller;"    " text-align: left;"    "}\n"    "#tbl tr > td {"    " padding-left: 1em;"
Roxen.git/server/config_interface/dbs/browser.pike:94:    "#tbl tr > th {"    " font-weight: bold;"    " background-color: &usr.matrix12;;"    " padding-left: 1em;"    "}\n"    "#tbl tr > *:first-child {"    " padding-left: 0;"    "}\n"    "</style>"    -  "<a href='browser.pike?db=" + db + "'><gbutton>Back</gbutton></a><br/><br/>" +  "<a href='browser.pike?db=" + db + "&amp;&usr.set-wiz-id;'><gbutton>Back</gbutton></a><br/><br/>"       "<table id='tbl' cellspacing='0' cellpadding='1'>"    "<thead>"    "<tr>"    "<th>Target</th>"    "<th>Result</th>"    "<th>Time</th>"    "</tr>"    "</thead>"    "<tbody>";
Roxen.git/server/config_interface/dbs/browser.pike:130:    t2 = (time(t)-t1);    t3 += t2;       if (q->Msg_text = "OK")    result = "<font color='green'>OK</font>";    else    result = "<font color='red'>Failed: " + q->Msg_text + "</font>";    }       res += "<tr>" + -  "<td><a href='browser.pike?db=" + db + "'>" + db + "</a>.<a href='browser.pike?db=" + db + "&amp;table=" + m->Name + "'>" + m->Name + "</a></td>" + +  "<td><a href='browser.pike?db=" + db + "&amp;&usr.set-wiz-id;'>" + db + "</a>.<a href='browser.pike?db=" + db + "&amp;table=" + m->Name + "&amp;&usr.set-wiz-id;'>" + m->Name + "</a></td>" +    "<td><b>" + result + "</b></td>" +    "<td>" + t2 + " sec</td>" +    "</tr>";    }    }    res += "<tr><td colspan='2'>Total:</td><td>" + t3 + " sec</td></tr></tbody></table><br/>";       return res;   }   
Roxen.git/server/config_interface/dbs/browser.pike:163:    "#tbl tr > th {"    " font-weight: bold;"    " background-color: &usr.matrix12;;"    " padding-left: 1em;"    "}\n"    "#tbl tr > *:first-child {"    " padding-left: 0;"    "}\n"    "</style>"    -  "<a href='browser.pike?db=" + db + "'><gbutton>Back</gbutton></a><br/><br/>" +  "<a href='browser.pike?db=" + db + "&amp;&usr.set-wiz-id;'><gbutton>Back</gbutton></a><br/><br/>"       "<table id='tbl' cellspacing='0' cellpadding='1'>"    "<thead>"    "<tr>"    "<th>Target</th>"    "<th>Result</th>"    "<th>Time</th>"    "</tr>"    "</thead>"    "<tbody>";
Roxen.git/server/config_interface/dbs/browser.pike:199:    t2 = (time(t)-t1);    t3 += t2;       if (q->Msg_text = "OK")    result = "<font color='green'>OK</font>";    else    result = "<font color='red'>Failed: " + q->Msg_text + "</font>";    }       res += "<tr>" + -  "<td><a href='browser.pike?db=" + db + "'>" + db + "</a>.<a href='browser.pike?db=" + db + "&amp;table=" + m->Name + "'>" + m->Name + "</a></td>" + +  "<td><a href='browser.pike?db=" + db + "&amp;&usr.set-wiz-id;'>" + db + "</a>.<a href='browser.pike?db=" + db + "&amp;table=" + m->Name + "&amp;&usr.set-wiz-id;'>" + m->Name + "</a></td>" +    "<td><b>" + result + "</b></td>" +    "<td>" + t2 + " sec</td>" +    "</tr>";    }    }    res += "<tr><td colspan='2'>Total:</td><td>" + t3 + " sec</td></tr></table><br/>";       return res;}      mixed query( mixed ... args ) {
Roxen.git/server/config_interface/dbs/browser.pike:236:    return    "<b>"+_(405,"Directory")+":</b> <input name='dir' size='60' value='auto' /><br />"    "<i>" + sprintf (_(1061, #"\   The directory the backup will be saved in. If you chose auto, Roxen   will generate a directory name that includes the database name and   today's date in <tt>$VARDIR/backup</tt> (%s)."),    combine_path (getcwd(), roxen_path ("$VARDIR/backup"))) +    "</i>"    "<table width='100%'><tr><td valign=top>"    "<input type=hidden name=action value='&form.action;' />" -  "<submit-gbutton2 name='ok'>"+_(201,"OK")+"</submit-gbutton2></td>\n" -  "<td valign=top align=right><cf-cancel href='"+ -  Roxen.html_encode_string(id->not_query)+ -  "?db="+Roxen.html_encode_string(id->variables->db)+"'/>" +  "<cf-cancel href='"+ Roxen.html_encode_string(id->not_query)+ +  "?db="+Roxen.html_encode_string(id->variables->db)+"&amp;&usr.set-wiz-id;'/>" +  "<td valign=top align=right><submit-gbutton2 name='ok'>"+_(201,"OK")+ +  "</submit-gbutton2></td>\n"    "</td>\n</table>\n";   }    - mixed move_db( string db, RequestID id ) + mixed configure_ext_db_con( string db, RequestID id )   { -  +  if( DBManager.is_internal( db ) ) { +  error("Configure external database connection not possible for internal " +  "databases."); +  }    string warning=""; -  int internal = DBManager.is_internal( db ); +     if( id->variables["ok.x"] )    { -  if( !internal ) -  { -  if( !strlen(id->variables->url) ) +  if( !strlen(id->variables->url) ) {    warning= "<font color='&usr.warncolor;'>"    +_(406,"Please specify an URL to define an external database")+    "</font>"; -  else if( mixed err = catch( Sql.Sql( id->variables->url ) ) ) +  } else if( mixed err = catch( Sql.Sql( id->variables->url ) ) ) {    warning = sprintf("<font color='&usr.warncolor;'>"+    _(407,"It is not possible to connect to %s.")+    "<br /> (%s)"    "</font>",    id->variables->url,    describe_error(err));    }    if( !strlen( warning ) )    switch( id->variables->name )    {    case "":    warning = "<font color='&usr.warncolor;'>"+ -  _(408,"Please specify a name for the database")+ +  _(1146,"Please specify a name for the database connection.")+    "</font>";    break;    case "mysql":    case "roxen":    warning = sprintf("<font color='&usr.warncolor;'>"+ -  _(409,"%s is an internal database, used by Roxen. " +  _(1147,"<tt>%s</tt> is an internal database, used by Roxen. "    "Please select another name.")+    "</font>", id->variables->name );    break;    default:    if( Roxen.is_mysql_keyword( id->variables->name ) )    warning = sprintf("<font color='&usr.warncolor;'>"+ -  _(410,"%s is a MySQL keyword, used by MySQL. " +  _(1148,"<tt>%s</tt> is a MySQL keyword, used by MySQL. "    "Please select another name.")+    "</font>", id->variables->name );    catch { -  if( DBManager.cached_get( id->variables->name ) && -  db != id->variables->name ) +  // Check name first since DBManager.get_db_url_info() ignores +  // trailing spaces in db name. +  if( !(DBManager.valid_db_name( id->variables->name )) ) +  {    warning = sprintf("<font color='&usr.warncolor;'>"+ -  _(529,"the database %s does already exist")+ +  _(1149,"<span style=\"white-space: pre;\">" +  "'<tt>%s</tt>'</span> " +  "is not a valid database name. " +  "Please select another name.")+    "</font>", id->variables->name ); -  // FIXME: Also check if the name is a valid db name. +  } +  else if( db != id->variables->name && +  DBManager.get_db_url_info( id->variables->name ) ) +  { +  warning = sprintf("<font color='&usr.warncolor;'>"+ +  _(529,"A database with name <tt>%s</tt> " +  "already exists. Please select another name.")+ +  "</font>", id->variables->name ); +  }    };    break;    }    if( !strlen( warning ) )    { -  // In all cases, create the new db. -  if(!(DBManager.get_db_url_info(id->variables->name))) { -  DBManager.create_db(id->variables->name, id->variables->url, -  internal, id->variables->group); -  } else { -  DBManager.set_url(id->variables->name, -  id->variables->url, -  internal); -  } -  -  // Intern -  // Copy if name has changed. -  // Extern -  // Just copy the meta information. -  if(internal) -  { -  // Internal db, use the backup thingies to copy the data +     if( db != id->variables->name )    { -  DBManager.backup( db, "/tmp/tmpdb" ); -  DBManager.restore( db, "/tmp/tmpdb", id->variables->name ); -  DBManager.delete_backup( db, "/tmp/tmpdb" ); -  } -  } -  switch( id->variables->what ) -  { -  case "copy": // copy, no delete -  if( db != id->variables->name ) +  DBManager.create_db( id->variables->name, +  id->variables->url, +  0, +  id->variables->group );    DBManager.copy_db_md( db, id->variables->name ); -  // Done. -  break; -  -  case "move": // move & delete -  // Delete the old data. -  if( db != id->variables->name ) -  { -  DBManager.copy_db_md( db, id->variables->name ); -  if( !strlen(warning) ) +     DBManager.drop_db( db );    } -  break; +  else if( id->variables->url != DBManager.db_url( db ) ) +  { +  // Only url has changed. +  DBManager.set_url( db, id->variables->url, 0 );    } -  +  // else nothing has changed...    return Roxen.http_redirect( "/dbs/", id );    }    } -  if(!id->variables->name) +  if( !id->variables->name )    id->variables->name = db;       if( !id->variables->url )    id->variables->url = DBManager.db_url( db ) || "";       return -  "<gtext scale=0.6>"+_(414,"Copy or rename this database")+"</gtext><br />\n" +  "<gtext scale=0.6>"+_(414,"Configure external database connection")+"</gtext><br />\n"    +warning+    "<table>\n"       " <tr>\n" -  " <td><b>"+_(415,"Action")+":</b></td>\n" -  " <td><default variable='form.what'>\n" -  " <select name='what'>\n" -  " <option value='copy'>"+_(416,"Copy the data to a new database")+"</option>\n" -  " <option value='move'>"+_(417,"Rename database")+"</option>\n" -  " </select></default>\n" -  " </td>\n" -  " </tr>\n" -  " <tr>\n" -  " <td><b>"+_(418,"New name")+":</b></td>\n" +  " <td><b>"+_(418,"Name")+":</b></td>\n"    " <td><input name='name' value='&form.name;'/></td>\n"    " </tr>\n"       " <tr>\n"    " <td valign=top colspan='2'>\n" -  " <i>"+_(530,"The new name of the database. To make it easy on " -  "your users, use all lowercaps characters, and avoid hard to type " -  "characters.")+"</i>\n" +  " <i>"+_(530,"The name for the database. It is recommended to " +  "use only lowercase letters <tt>[a-z]</tt>, numbers " +  "and <tt>-</tt> (dash).")+"</i>\n"    " </td>\n"    " </tr>\n"+    -  (internal?"": +     " <tr>\n"    " <td><nbsp><b>URL:</b></nbsp></td>\n"    " <td colspan='3'><input name='url' size=50 value='&form.url;'/></td>\n" -  " </tr>\n" -  " <tr>" -  " <td colspan='4'><i>\n"+ -  " "+_(422,"This URL is only used for </i>External<i> databases, it is " -  "totally ignored for databases defined internally in Roxen. ")+"\n</i>\n" -  " </td>" -  " </tr>\n")+ +  " </tr>\n"+       "</table>\n"+    "<table width='100%'><tr><td>"    "<input type=hidden name=action value='&form.action;' />" -  "<submit-gbutton2 name='ok'>"+_(201,"OK")+"</submit-gbutton2></td>\n" +  "<cf-cancel href='" + Roxen.html_encode_string(id->not_query) + +  "?db=" + Roxen.html_encode_string(id->variables->db) + +  "&amp;&usr.set-wiz-id;'/></td>\n"    "<td align=right>" -  "<cf-cancel href='"+Roxen.html_encode_string(id->not_query)+ -  "?db="+ -  Roxen.html_encode_string(id->variables->db)+"'/>" +  "<submit-gbutton2 name='ok'>" + _(201,"OK") + "</submit-gbutton2>"    "</td>\n</table>\n";   }      mixed delete_db( string db, RequestID id )   {    string msg;    if( DBManager.is_internal( db ) )    msg = (string)_(361, "Are you sure you want to delete the database %s "    "and the data?");    else
Roxen.git/server/config_interface/dbs/browser.pike:524:    return "";       string res = #"    <script type='text/javascript'>    function switch_db( objSel ) {    if( objSel.selectedIndex == 0) {    return;    }    var selValue = objSel.options[objSel.selectedIndex].value;    if(selValue != '&form.db:js;') { -  window.location.href = window.location.pathname + '?db=' + escape( selValue ); +  window.location.href = window.location.pathname + '?db=' + escape( selValue ) + '\x26&usr.set-wiz-id:js;';    }    }    </script>    <select name='db' onchange='switch_db(this)'>    <option value=''>Switch to other DB</option>\n";    foreach( sort(indices(q)), string d ) {    res += sprintf( "<option value='%s'%s>%s</option>\n", d,    (d == id->variables->db)? "selected='selected'": "", d);    }    return res + "</select><noscript><input type='submit' value='Switch db'/></noscript>\n";
Roxen.git/server/config_interface/dbs/browser.pike:661:    "#res > * > tr {"    " vertical-align: top;"    "}\n"    "#res > * > tr > * {"    " border: 1px solid &usr.matrix22;;"    "}\n"    "#res > * > tr > th {"    " font-weight: bold;"    " background-color: &usr.matrix12;;"    "}\n" +  "#res span.warn_exp {" +  " color: &usr.warncolor;;" +  " white-space: nowrap;" +  "}\n"    "</style>\n";       if( id->variables->action && actions[ id->variables->action ])    {    res += "<input type='hidden' name='db' value='&form.db:http;' />\n";    mixed tmp = actions[ id->variables->action ][1]( id->variables->db, id );    if( stringp( tmp ) )    return res+tmp+"\n</st-page></content></tmpl>";    if( tmp )    return tmp;
Roxen.git/server/config_interface/dbs/browser.pike:793:    "\n", "<br/>\n"))+    "</font></p>\n";    continue;    }    float qtime = (gethrtime()-h)/1000000.0;       if (!big_q)    // Query had no result or was empty/commented out.    continue;    +  do {    int qrows;    qres += "<p>\n" -  "<table id='res'><tr>"; +  "<table id='res'><tr class='tr-sticky'>"; +  // FIXME: Using id='res' above is wrong, as the tag +  // can be generated multiple times in the same +  // document. See also similar code further below.    multiset right_columns = (<>);    int column;       array(string) col_types = ({}); -  +  array(string) col_names = ({});       foreach( big_q->fetch_fields(), mapping field )    {    switch( field->type )    {    case "char": // Actually a TINYINT. -  +  case "tiny integer":    case "short":    case "int": -  +  case "integer":    case "long": -  +  case "long integer":    case "int24":    case "longlong":    right_columns[column]=1;    qres += "<th class='num'>";    col_types += ({"int"});    break; -  +  case "real":    case "float":    case "double":    right_columns[column]=1;    qres += "<th class='num'>";    col_types += ({"float"});    break;    case "decimal":    case "numeric":    qres += "<th class='num'>";    col_types += ({"string"});    break;    case "bit":    default:    qres += "<th>";    col_types += ({"string"});    }    qres += Roxen.html_encode_string (field->name) + "</th>\n"; -  +  col_names += ({ field->name });    column++;    }    qres += "</tr>";    -  +  mapping(string:string) mod_info = +  DBManager.module_table_info (id->variables->db, ""); +  +  Configuration c = !(<0, "">)[mod_info->conf] && +  roxen.find_configuration (mod_info->conf); +  RoxenModule m = c && !(<0, "">)[mod_info->module] && +  c->find_module (mod_info->module); +  +  // Find any column formatter callback in the DB's owner +  // module. See function prototype in base_server/module.pike. +  function(string,string,string,array(string),array(string),array(string), +  RequestID:string) format_col_cb = +  m && m->format_db_browser_value; +  array(int) formatted_total_size = allocate(sizeof(col_names), 0); +  if (id->variables->exp_fields == "disabled") +  format_col_cb = 0; +     while( array q = big_q->fetch_row() )    {    qrows++;    qres += "<tr>";    for( int i = 0; i<sizeof(q); i++ ) {    qres += right_columns[i] ? "<td class='num'>" : "<td>";    if( !q[i] )    qres += "<i>NULL</i>";    else if( intp( q[i] ) || col_types[i] == "int" )    qres += (string) (int) q[i];    else if( floatp( q[i] ) || col_types[i] == "float" )    qres += (string) (float) q[i];    else if( is_image( q[i] ) )    qres += -  "<img src='browser.pike?image="+store_image( q[i] )+ "' />"; +  "<img src='browser.pike?image=" + store_image( q[i] ) + +  "&amp;&usr.set-wiz-id;' />";    else {    mixed tmp = q[i]; -  if (is_deflated (q[i])) { +  int got_result; +  if (format_col_cb) { +  // Check for excessive amount of formatted data +  if (formatted_total_size[i] > MAX_TOTAL_FORMATTED_SIZE) { +  qres += +  "<span class='warn_exp'>" + +  "Total formatted data length exceeded &ndash; limit your query." +  "</span>"; +  got_result = 1; +  } else if (mixed formatted = +  format_col_cb (id->variables->db, +  id->variables->table, +  col_names[i], col_names, +  col_types, q, id)) { +  int formatted_len = sizeof(formatted); +  if ((formatted_len >= MAX_FIELD_FORMATTED_SIZE) && +  (id->variables->exp_fields == "auto")) { +  // This field alone is too big to display +  qres += +  "<span class='warn_exp'>" + +  "Skipping " + (formatted_len / 1024) + "K formatted data." +  "</span>"; +  got_result = 1; +  } else { +  formatted_total_size[i] += formatted_len; +  qres += formatted; +  got_result = 1; +  } +  } +  } +  +  if (!got_result) { +  if (is_deflated (tmp)) {    // is_deflated _may_ give false positives, hence the catch.    catch { -  tmp = Gz.inflate()->inflate (q[i]); +  tmp = Gz.inflate()->inflate (tmp);    };    }       if( is_encode_value( tmp ) )    qres += format_decode_value(tmp);    else if (String.width (tmp) > 8) {    // Let wide chars skip past the %q quoting, because    // it'll quote them to \u escapes otherwise.    string q = "";    int s;
Roxen.git/server/config_interface/dbs/browser.pike:879:    if (s < i) q += sprintf ("%q", tmp[s..i - 1])[1..<1];    q += sprintf ("%c", c);    s = i + 1;    }    q += sprintf ("%q", tmp[s..])[1..<1];    qres += Roxen.html_encode_string (q);    }    else    qres += Roxen.html_encode_string(sprintf("%q", tmp)[1..<1]);    } +  }    qres += "</td>";    }    qres += "</tr>\n";    }       qres += "</table>"+    sprintf( _(426,"Query took %[0].3fs, %[1]d rows in the reply")+    "\n</p>\n", qtime, qrows); -  +  +  if (!big_q->next_result) break; +  h = gethrtime(); +  if (mixed err = catch (big_q = big_q->next_result())) { +  qres += "<p><font color='&usr.warncolor;'>"+ +  sprintf((string)_(1062,"Error running query %d: %s"), i + 1, +  replace (Roxen.html_encode_string ( +  String.trim_all_whites (describe_error(err))), +  "\n", "<br/>\n"))+ +  "</font></p>\n"; +  break;    } -  +  qtime = (gethrtime()-h)/1000000.0; +  if (!big_q) break; +  +  // More results available. +  } while(1);    } -  +  }       if( !(<0, "">)[id->variables->table] )    res += "<input type=hidden name='table' value='&form.table:http;' />\n";       // DB switcher and title.       res += "<p>"    "<table><tr valign='center'>"    "<td><cimg border='0' format='gif' src='&usr.database-small;' alt='' "    "max-height='20'/></td>" +
Roxen.git/server/config_interface/dbs/browser.pike:913:    if (db_connect_error)    res += "<p><font color='red'>" +    _(1063, "Error connecting to database: ") +    Roxen.html_encode_string (describe_error (db_connect_error)) +    "</font></p>\n";       // Bullet list with generic database info.       res += "<p><ul>\n";    -  if (id->variables->db == "local") +  switch(id->variables->db) { +  case "local":    res += "<li>" +    _(546, "Internal data that cannot be shared between servers.") + "</li>\n"; -  else if (id->variables->db == "shared") +  break; +  case "shared":    res += "<li>" +    _(547, "Internal data that may be shared between servers.") + "</li>\n"; -  else if( !url ) +  break; +  case "mysql": +  res += "<li>" + +  _(1140, "MySQL/MariaDB-internal database.") + "</li>\n"; +  break; +  case "roxen": +  res += "<li>" + +  _(1141, "Roxen-internal database.") + "</li>\n"; +  break; +  default: +  if( !url )    res += "<li>Internal database.</li>\n";    else    res += "<li>Database URL: " + Roxen.html_encode_string(url)+"</li>\n"; -  +  break; +  }       mapping(string:string) db_info =    DBManager.module_table_info (id->variables->db, "");    if (string owner = format_table_owner (db_info))    res += "<li>" + sprintf((string)_(428,"Defined by %s."), owner) +    "</li>\n";    if (string c = db_info->comment) {    c = String.trim_all_whites (c);    if (c != "")    res += "<li>" + Roxen.html_encode_string (c) + "</li>\n";
Roxen.git/server/config_interface/dbs/browser.pike:946:    if (default_charset) {    res += "<li>" + _(548,"Default charset:") +    Roxen.html_encode_string(default_charset) + "</li>";    }       res +="<li>" +    sprintf( (string)    _(506,"Member of the %s database group."),    "<a href='edit_group.pike?group="+    Roxen.http_encode_url(DBManager.db_group( id->variables->db ))+ -  "'>" + +  "&amp;&usr.set-wiz-id;'>" +    DBManager.get_group( DBManager.db_group( id->variables->db ) )    ->lname +    "</a>")    + "</li>";    -  +  string schedule = DBManager.db_schedule(id->variables->db); +  if (schedule) { +  res += "<li>" + +  sprintf( (string)_(1114, "Backuped via the %s backup schedule."), +  "<a href='schedules.html'>" + +  Roxen.html_encode_string(schedule) + +  "</a>") + +  "</li>"; +  } else { +  res += "<li><b>" + +  _(1115, "Not a member of any backup schedule.") + +  "</b></li>"; +  }    res += "</ul></p>\n";       if (db) {    // The database table list.       res += "<p><table id='tbls' border='0' cellpadding='2' cellspacing='0'>";       array table_data = ({});    int sort_ok, got_owner_column;   
Roxen.git/server/config_interface/dbs/browser.pike:1031:    return res+ "</table>";    };       void add_table_info( string table, mapping tbi )    {    mapping(string:string) tbl_info =    DBManager.module_table_info (id->variables->db, table);       int deep_info = id->variables->table == table;    -  string res = "<tr>" +  string res = +  "<tr" + +  (tbl_info->inhibit_backups == "yes"? +  " bgcolor='&usr.fade1;' fgcolor='&usr.top-fgcolor;'":"") + +  ">"    "<td style='white-space: nowrap'>"    "<a href='browser.pike?sort=&form.sort:http;&amp;" -  "db=&form.db:http;" + +  "db=&form.db:http;&amp;&usr.set-wiz-id;" +    (deep_info ? "" : "&amp;table="+Roxen.http_encode_url(table)) +"'>"+    "<cimg style='vertical-align: -2px' border='0' format='gif'"    " src='&usr.table-small;' alt='' max-height='12'/> " +    table+"</a></td>"    "<td class='num'>"+    (!tbi || zero_type (tbi->rows) ? "" : tbi->rows) + "</td>"    "<td class='num'>" +    (!tbi || zero_type (tbi->data_length) ? "" :    sprintf ("%d KiB",    ((int)tbi->data_length+(int)tbi->index_length) / 1024)) +    "</td>";       string owner;    if ((db_info->conf || "") != (tbl_info->conf || ""))    owner = format_table_owner (tbl_info, 0);    else if ((db_info->module || "") != (tbl_info->module || ""))    owner = format_table_owner (tbl_info, 1); -  +  res += "<td>";    if (owner) { -  res += "<td>" + String.capitalize (owner) + "</td>"; +  res += owner;    got_owner_column = 1;    } -  else res += "<td></td>"; +  res += "</td>";       if (deep_info) {    res += "</tr>\n<tr class='tbl-details'><td colspan='5'>";       if (tbl_info->comment)    sscanf( tbl_info->comment, "%s\0%s",    tbl_info->tbl, tbl_info->comment );       if( tbl_info->tbl && tbl_info->tbl != table)    if( tbl_info->tbl != (string)0 )
Roxen.git/server/config_interface/dbs/browser.pike:1081:    res +=    sprintf((string) _(430,"The table is an anonymous table defined "    "by the module."), tbl_info->tbl ) + "<br/>\n";       if (string c = tbl_info->comment) {    c = String.trim_all_whites (c);    if (c != "" && c != "0")    res += Roxen.html_encode_string (c) + "<br/>\n";    }    +  if (tbl_info->inhibit_backups == "yes") { +  res += _(1142, "The table is not included in backups of this database.") + +  "<br />\n"; +  } +     res += deep_table_info (table) + "</td></tr>\n";    }    else    res += "</tr>\n";       if( tbi )    sort_ok = 1;       table_data += ({({    table,
Roxen.git/server/config_interface/dbs/browser.pike:1130:    " border='0' alt='&gt;'/>" : \    "")       if( sort_ok )    {    if (!got_owner_column)    // Try to hide the owner column when it's empty. Doesn't work    // in firefox 2.0, though.    res += "<col span='3'/><col style='visiblity: collapse'/>\n";    res += -  "<thead><tr>" -  "<th><a href='browser.pike?db=&form.db:http;&amp;table=&form.table:http;&amp;sort=name'>"+ +  "<thead><tr class='tr-sticky'>" +  "<th><a href='browser.pike?db=&form.db:http;&amp;table=&form.table:http;&amp;sort=name&amp;&usr.set-wiz-id;'>"+    SEL("name", 1) + _(376,"Name")+    "</a></th>\n" -  "<th class='num'><a href='browser.pike?db=&form.db:http;&amp;table=&form.table:http;&amp;sort=rows'>"+ +  "<th class='num'><a href='browser.pike?db=&form.db:http;&amp;table=&form.table:http;&amp;sort=rows&amp;&usr.set-wiz-id;'>"+    SEL("rows",0)+String.capitalize(_(374,"rows"))+    "</a></th>\n" -  "<th class='num'><a href='browser.pike?db=&form.db:http;&amp;table=&form.table:http;&amp;sort=size'>"+ +  "<th class='num'><a href='browser.pike?db=&form.db:http;&amp;table=&form.table:http;&amp;sort=size&amp;&usr.set-wiz-id;'>"+    SEL("size",0)+_(377,"Size")+    "</a></th>\n"    "<th>Owner</th>\n"    "</tr></thead>\n";    }       res += "<tbody>" + column( table_data, 3 )*"\n" +    "</tbody></table></p>\n";       // Query widget.    -  +  string formatter_options = +  "<span style='font-size: smaller;'>Smart field formatters: </span>" +  "<default variable='form.exp_fields'>" +  "<select name='exp_fields'>" +  " <option value='auto'>Enabled for data &lt; " + (MAX_FIELD_FORMATTED_SIZE / 1024) + "K</option>" +  " <option value='disabled'>Disabled</option>" +  " <option value='force'>Force expansion of long fields</option>" +  "</select>" +  "</default>" +  "<br />"; +  +  int db_has_formatters = 0; +  if (id->variables->db) { +  mapping(string:string) mod_info = +  DBManager.module_table_info (id->variables->db, ""); +  Configuration c = !(<0, "">)[mod_info->conf] && +  roxen.find_configuration (mod_info->conf); +  RoxenModule m = c && !(<0, "">)[mod_info->module] && +  c->find_module (mod_info->module); +  db_has_formatters = m && m->format_db_browser_value; +  } +     res +=    "<a name='dbquery'></a><p>"    "<textarea rows='12' cols='90' wrap='soft' name='query' "    " style='font-size: 90%'>" + -  Roxen.html_encode_string (id->variables->query) + "</textarea><br />" +  Roxen.html_encode_string (id->variables->query) + "</textarea><br />" + +  (db_has_formatters ? formatter_options : "") +    "<table><tr><td>"    "<submit-gbutton2 name=reset_q> "+_(378,"Reset query")+" </submit-gbutton2>"    "</td><td>"    "<submit-gbutton2 name=run_q> "+_(379,"Run query")+" </submit-gbutton2>"    "</td><td style='font-size: smaller; padding-left: 10px'>" +    _(1064, "Tip: Put '--' on a line to ignore everything below it.") +    "</td></tr></table></p>";       // Query result.       res += qres;    }       // Actions.       res += "<p>";    - #define ADD_ACTION(X) if(!actions[X][2] || \ -  DBManager.is_internal(id->variables->db) ) \ -  res += sprintf("<a href='%s?db=%s&amp;action=%s'><gbutton>%s</gbutton></a>\n",\ +  int flags = DBManager.is_internal(id->variables->db)*3; +  if (!flags) { +  mapping(string:mixed) url_info = +  DBManager.get_db_url_info(id->variables->db); +  if (url_info && has_prefix(url_info->path, "mysql://")) { +  // Is external mysql. +  flags = 2; +  } +  } +  + #define ADD_ACTION(X) if(!actions[X][2] || (actions[X][2] & flags) ) \ +  res += sprintf("<a href='%s?db=%s&amp;action=%s&amp;&usr.set-wiz-id;'><gbutton>%s</gbutton></a>\n",\    id->not_query, id->variables->db, X, actions[X][0] )       switch( id->variables->db )    {    case "local": -  foreach( ({ "move","backup","optimize","repair" }), string x ) +  foreach( ({ "backup","optimize","repair","schedule" }), string x )    ADD_ACTION( x );    break;       default: -  foreach( sort(indices( actions )), string x ) +  array(string) action_ids = sort( indices( actions ) ); +  if (DBManager.is_internal( id->variables->db )) { +  action_ids -= ({ "configure_ext_db_con" }); +  } +  foreach( action_ids, string x )    ADD_ACTION( x );    break;    }    return res+"</p></st-page></subtablist></cv-split></content></tmpl>";   }