העברת סקריפטים לסביבת זמן הריצה של V8

סביבת זמן הריצה של Rhino תושבת ב-31 בינואר 2026 או לאחר מכן. אם יש לכם סקריפט קיים שמשתמש בסביבת זמן הריצה של Rhino, אתם צריכים להעביר את הסקריפט ל-V8.

לרוב, הדרישה היחידה להוספת תחביר ותכונות של V8 לסקריפט היא הפעלת זמן הריצה של V8. עם זאת, יש קבוצה קטנה של חוסר תאימות והבדלים אחרים שיכולים לגרום לסקריפט להיכשל או להתנהג באופן לא צפוי בסביבת זמן הריצה של V8. כשמעבירים סקריפט לשימוש ב-V8, צריך לחפש את הבעיות האלה בפרויקט הסקריפט ולתקן את כל הבעיות שמאתרים.

תהליך ההעברה ל-V8

כדי להעביר סקריפט ל-V8, פועלים לפי השלבים הבאים:

  1. מפעילים את זמן הריצה של V8 בסקריפט. אפשר לבדוק את runtimeVersion באמצעות קובץ המניפסט של פרויקט Google Apps Script.
  2. חשוב לעיין בבעיות התאימות הבאות. בודקים את הסקריפט כדי לראות אם יש בו בעיות תאימות. אם יש בעיה אחת או יותר, משנים את קוד הסקריפט כדי לפתור אותה.
  3. חשוב לעיין בקפידה בההבדלים האחרים שבהמשך. בודקים את הסקריפט כדי לראות אם אחד מההבדלים שצוינו משפיע על ההתנהגות של הקוד. משנים את הסקריפט כדי לתקן את ההתנהגות.
  4. אחרי שתתקנו את כל חוסר התאימות או הבדלים אחרים שגיליתם, תוכלו להתחיל לעדכן את הקוד כדי להשתמש בתחביר V8 ובתכונות אחרות.
  5. אחרי שמסיימים את ההתאמות בקוד, חשוב לבדוק את הסקריפט ביסודיות כדי לוודא שהוא פועל כמצופה.
  6. אם הסקריפט הוא אפליקציית אינטרנט או תוסף שפורסם, צריך ליצור גרסה חדשה של הסקריפט עם ההתאמות ל-V8, ולהפנות את הפריסה לגרסה החדשה שנוצרה. כדי שהגרסה V8 תהיה זמינה למשתמשים, צריך לפרסם מחדש את הסקריפט עם הגרסה הזו.
  7. אם הסקריפט שלכם משמש כספרייה, צריך ליצור פריסה חדשה עם ניהול גרסאות של הסקריפט. צריך להודיע על הגרסה החדשה הזו לכל הסקריפטים ולכל המשתמשים שמשתמשים בספרייה, ולהנחות אותם לעדכן לגרסה שתומכת ב-V8. מוודאים שגרסאות ישנות יותר של הספרייה שמבוססות על Rhino לא נמצאות יותר בשימוש פעיל או בגישה.
  8. מוודאים שאין מקרים שבהם הסקריפט עדיין פועל בסביבת זמן הריצה של Rhino מדור קודם. מוודאים שכל הפריסות משויכות לגרסה שנמצאת ב-V8. העברה לארכיון של פריסות ישנות. בודקים את כל הגרסאות ומוחקים את הגרסאות שלא משתמשות בסביבת ההרצה של V8.

חוסר תאימות

לרוע המזל, סביבת זמן הריצה המקורית של Apps Script שמבוססת על Rhino אפשרה כמה התנהגויות לא סטנדרטיות של ECMAScript. מנוע V8 תואם לתקנים, ולכן אין תמיכה בהתנהגויות האלה אחרי המעבר. אם לא תתקנו את הבעיות האלה, תקבלו שגיאות או שהסקריפט לא יפעל כראוי אחרי שתפעילו את זמן הריצה V8.

בקטעים הבאים מתוארים כל אחד מההתנהגויות האלה והשלבים שצריך לבצע כדי לתקן את קוד הסקריפט במהלך ההעברה ל-V8.

יש להימנע מ-for each(variable in object)

ההצהרה for each (variable in object) נוספה ל-JavaScript 1.6, והוסרה לטובת for...of.

כשמעבירים סקריפט ל-V8, צריך להימנע משימוש בfor each (variable in object) הצהרות.

במקום זאת, צריך להשתמש ב-for (variable in object):

// Rhino runtime
var obj = {a: 1, b: 2, c: 3};

// Don't use 'for each' in V8
for each (var value in obj) {
  Logger.log("value = %s", value);
}
      
// V8 runtime
var obj = {a: 1, b: 2, c: 3};

for (var key in obj) {  // OK in V8
  var value = obj[key];
  Logger.log("value = %s", value);
}
      

יש להימנע מ-Date.prototype.getYear()

בזמן הריצה המקורי של Rhino, ‫Date.prototype.getYear() מוחזרות שנים בנות שתי ספרות לשנים מ-1900 עד 1999, אבל שנים בנות ארבע ספרות לתאריכים אחרים. זו הייתה ההתנהגות ב-JavaScript 1.2 ובגרסאות קודמות.

בסביבת זמן הריצה של V8, Date.prototype.getYear() הפונקציה מחזירה את השנה פחות 1900, כנדרש בתקני ECMAScript.

כשמעבירים סקריפט ל-V8, תמיד משתמשים ב-Date.prototype.getFullYear(), שמחזיר שנה בת ארבע ספרות ללא קשר לתאריך.

אל תשתמשו במילות מפתח שמורות כשמות

ב-ECMAScript אסור להשתמש במילות מפתח שמורות מסוימות בשמות של פונקציות ומשתנים. סביבת הריצה של Rhino אפשרה שימוש בהרבה מהמילים האלה, ולכן אם אתם משתמשים בהן בקוד, אתם צריכים לשנות את השם של הפונקציות או המשתנים.

כשמעבירים סקריפט ל-V8, צריך להימנע מלתת למשתנים או לפונקציות שמות שכוללים אחת ממילות המפתח השמורות. משנים את השם של כל משתנה או פונקציה כדי לא להשתמש בשם מילת המפתח. שימושים נפוצים במילות מפתח כשמות הם class, import ו-export.

יוצא מן הכלל הוא שאפשר להשתמש במילות מפתח שמורות (בכל סביבות זמן הריצה) במילולי אובייקטים:

function class() {}     // Syntax error in V8.
var obj = { class: 1 }; // Allowed.

הימנעות מהקצאה מחדש של משתני const

בזמן הריצה המקורי של Rhino, אפשר להצהיר על משתנה באמצעות const, כלומר הערך של הסמל לא משתנה וההקצאות העתידיות לסמל מתעלמות.

בזמן הריצה החדש של V8, מילת המפתח const תואמת לתקן, והקצאה למשתנה שהוגדר כ-const גורמת לשגיאת זמן ריצה TypeError: Assignment to constant variable.

כשמעבירים את הסקריפט לגרסה 8, לא מנסים להקצות מחדש את הערך של משתנה const:

// Rhino runtime
const x = 1;
x = 2;          // No error
console.log(x); // Outputs 1
      
// V8 runtime
const x = 1;
x = 2;          // Throws TypeError
console.log(x); // Never executed
      

הימנעו משימוש במחרוזות XML ובאובייקט XML

התוסף הלא סטנדרטי הזה ל-ECMAScript מאפשר לפרויקטים של Apps Script להשתמש ישירות בתחביר XML.

כשמעבירים את הסקריפט ל-V8, מומלץ להימנע משימוש בליטרלים ישירים של XML או באובייקט XML.

במקום זאת, משתמשים ב-XmlService כדי לנתח XML:

// V8 runtime
var incompatibleXml1 = <container><item/></container>;             // Don't use
var incompatibleXml2 = new XML('<container><item/></container>');  // Don't use

var xml3 = XmlService.parse('<container><item/></container>');     // OK
      

אל תיצרו פונקציות איטרציה בהתאמה אישית באמצעות __iterator__

ב-JavaScript 1.7 נוספה תכונה שמאפשרת להוסיף איטרטור בהתאמה אישית לכל מחלקה על ידי הצהרה על פונקציית __iterator__ באב-טיפוס של המחלקה. התכונה הזו נוספה גם לסביבת זמן הריצה של Rhino ב-Apps Script כדי להקל על המפתחים. עם זאת, התכונה הזו אף פעם לא הייתה חלק מתקן ECMA-262 והיא הוסרה ממנועי JavaScript שתואמים ל-ECMAScript. בסקריפטים שמשתמשים ב-V8 אי אפשר להשתמש בבניית האיטרטור הזה.

כשמעבירים את הסקריפט ל-V8, לא מומלץ להשתמש בפונקציה __iterator__ כדי ליצור איטרטורים בהתאמה אישית. במקום זאת, צריך להשתמש באיטרטורים של ECMAScript 6.

כדאי להביא בחשבון את מבנה המערך הבא:

// Create a sample array
var myArray = ['a', 'b', 'c'];
// Add a property to the array
myArray.foo = 'bar';

// The default behavior for an array is to return keys of all properties,
//  including 'foo'.
Logger.log("Normal for...in loop:");
for (var item in myArray) {
  Logger.log(item);            // Logs 0, 1, 2, foo
}

// To only log the array values with `for..in`, a custom iterator can be used.
      

בדוגמאות הקוד הבאות מוצג איך אפשר ליצור איטרטור בסביבת זמן הריצה של Rhino, ואיך אפשר ליצור איטרטור חלופי בסביבת זמן הריצה של V8:

// Rhino runtime custom iterator
function ArrayIterator(array) {
  this.array = array;
  this.currentIndex = 0;
}

ArrayIterator.prototype.next = function() {
  if (this.currentIndex
      >= this.array.length) {
    throw StopIteration;
  }
  return "[" + this.currentIndex
    + "]=" + this.array[this.currentIndex++];
};

// Direct myArray to use the custom iterator
myArray.__iterator__ = function() {
  return new ArrayIterator(this);
}


Logger.log("With custom Rhino iterator:");
for (var item in myArray) {
  // Logs [0]=a, [1]=b, [2]=c
  Logger.log(item);
}
      
// V8 runtime (ECMAScript 6) custom iterator
myArray[Symbol.iterator] = function() {
  var currentIndex = 0;
  var array = this;

  return {
    next: function() {
      if (currentIndex < array.length) {
        return {
          value: "[${currentIndex}]="
            + array[currentIndex++],
          done: false};
      } else {
        return {done: true};
      }
    }
  };
}

Logger.log("With V8 custom iterator:");
// Must use for...of since
//   for...in doesn't expect an iterable.
for (var item of myArray) {
  // Logs [0]=a, [1]=b, [2]=c
  Logger.log(item);
}
      

בזמן הריצה של V8, צריך להשתמש ב-for...of כשמבצעים מעבר על מערכים עם איטרטורים מותאמים אישית, כי for..in לא מצפה לאובייקטים שניתן לבצע עליהם איטרציה.

הימנעות מסעיפי catch מותנים

זמן הריצה של V8 לא תומך בסעיפי catch מותנים של catch..if, כי הם לא עומדים בתקן.

כשמעבירים את הסקריפט ל-V8, צריך להעביר את כל התנאים של catch לתוך גוף ה-catch:

// Rhino runtime

try {
  doSomething();
} catch (e if e instanceof TypeError) {  // Don't use
  // Handle exception
}
      
// V8 runtime
try {
  doSomething();
} catch (e) {
  if (e instanceof TypeError) {
    // Handle exception
  }
}

אל תשתמשו ב-Object.prototype.toSource()

‫JavaScript 1.3 כלל שיטה Object.prototype.toSource() שלא הייתה אף פעם חלק מתקן ECMAScript. אין תמיכה בזמן הריצה של V8.

כשמעבירים את הסקריפט ל-V8, צריך להסיר מהקוד את כל השימושים ב-Object.prototype.toSource().

הבדלים אחרים

בנוסף לחוסר התאימות שצוין למעלה, שעלול לגרום לכשלים בסקריפט, יש עוד כמה הבדלים שאם לא יתוקנו, עלולים לגרום להתנהגות בלתי צפויה של סקריפט בסביבת ההרצה של V8.

בקטעים הבאים מוסבר איך לעדכן את קוד הסקריפט כדי להימנע מהפתעות לא צפויות כאלה.

שינוי פורמט התאריך והשעה בהתאם למיקום

השיטות Date,‏ toLocaleString(),‏ toLocaleDateString() ו-toLocaleTimeString() פועלות באופן שונה בסביבת זמן הריצה של V8 בהשוואה ל-Rhino.

ב-Rhino, פורמט ברירת המחדל הוא הפורמט הארוך, וכל הפרמטרים שמועברים מוזנחים.

בזמן הריצה של V8, פורמט ברירת המחדל הוא הפורמט הקצר, והפרמטרים שמועברים מטופלים בהתאם לתקן ECMA (פרטים נוספים זמינים במסמכי התיעוד של toLocaleDateString()).

כשמעבירים את הסקריפט ל-V8, צריך לבדוק את הציפיות של הקוד לגבי הפלט של שיטות תאריך ושעה ספציפיות ללוקאל ולהתאים אותן:

// Rhino runtime
var event = new Date(
  Date.UTC(2012, 11, 21, 12));

// Outputs "December 21, 2012" in Rhino
console.log(event.toLocaleDateString());

// Also outputs "December 21, 2012",
//  ignoring the parameters passed in.
console.log(event.toLocaleDateString(
    'de-DE',
    { year: 'numeric',
      month: 'long',
      day: 'numeric' }));
// V8 runtime
var event = new Date(
  Date.UTC(2012, 11, 21, 12));

// Outputs "12/21/2012" in V8
console.log(event.toLocaleDateString());

// Outputs "21. Dezember 2012"
console.log(event.toLocaleDateString(
    'de-DE',
    { year: 'numeric',
      month: 'long',
      day: 'numeric' }));
      

להימנע משימוש ב-Error.fileName וב-Error.lineNumber

בזמן הריצה של V8, האובייקט Error של JavaScript הרגיל לא תומך ב-fileName או ב-lineNumber כפרמטרים של בנאי או כמאפיינים של אובייקט.

כשמעבירים את הסקריפט ל-V8, צריך להסיר את כל התלות ב-Error.fileName וב-Error.lineNumber.

אפשרות אחרת היא להשתמש ב-Error.prototype.stack. גם המידע הזה לא סטנדרטי, אבל הוא נתמך ב-V8. הפורמט של ה-stack trace שנוצר בשתי הפלטפורמות שונה מעט:

// Rhino runtime Error.prototype.stack
// stack trace format
at filename:92 (innerFunction)
at filename:97 (outerFunction)
// V8 runtime Error.prototype.stack
// stack trace format
Error: error message
at innerFunction (filename:92:11)
at outerFunction (filename:97:5)
      

שינוי הטיפול באובייקטים של enum שהומרו למחרוזת

בזמן הריצה המקורי של Rhino, השימוש בשיטה JSON.stringify() של JavaScript באובייקט enum מחזיר רק {}.

בגרסה 8, שימוש באותה שיטה באובייקט enum מחזיר את שם ה-enum.

כשמעבירים את הסקריפט ל-V8, צריך לבדוק ולשנות את הציפיות של הקוד לגבי הפלט של JSON.stringify() באובייקטים של enum:

// Rhino runtime
var enumName =
  JSON.stringify(Charts.ChartType.BUBBLE);

// enumName evaluates to {}
// V8 runtime
var enumName =
  JSON.stringify(Charts.ChartType.BUBBLE);

// enumName evaluates to "BUBBLE"

שינוי הטיפול בפרמטרים לא מוגדרים

בזמן הריצה המקורי של Rhino, העברת undefined לשיטה כפרמטר גרמה להעברת המחרוזת "undefined" לשיטה הזו.

ב-V8, העברת undefined לשיטות שקולה להעברת null.

כשמעבירים את הסקריפט ל-V8, צריך לבדוק את הקוד ולשנות את ההגדרות שלו לגבי undefinedפרמטרים:

// Rhino runtime
SpreadsheetApp.getActiveRange()
    .setValue(undefined);

// The active range now has the string
// "undefined"  as its value.
      
// V8 runtime
SpreadsheetApp.getActiveRange()
    .setValue(undefined);

// The active range now has no content, as
// setValue(null) removes content from
// ranges.

שינוי הטיפול ב-this גלובלי

סביבת זמן הריצה של Rhino מגדירה הקשר מיוחד משתמע לסקריפטים שמשתמשים בה. קוד הסקריפט פועל בהקשר המרומז הזה, ששונה מההקשר הגלובלי בפועל this. המשמעות היא שהפניות אל 'this' בקוד מוערכות למעשה בהקשר המיוחד, שכולל רק את הקוד והמשתנים שהוגדרו בסקריפט. השימוש ב-this לא כולל את השירותים המובנים של Apps Script ואת האובייקטים של ECMAScript. המצב הזה היה דומה למבנה JavaScript הבא:

// Rhino runtime

// Apps Script built-in services defined here, in the actual global context.
var SpreadsheetApp = {
  openById: function() { ... }
  getActive: function() { ... }
  // etc.
};

function() {
  // Implicit special context; all your code goes here. If the global this
  // is referenced in your code, it only contains elements from this context.

  // Any global variables you defined.
  var x = 42;

  // Your script functions.
  function myFunction() {
    ...
  }
  // End of your code.
}();

ב-V8, ההקשר המיוחד המרומז הוסר. משתנים ופונקציות גלובליים שמוגדרים בסקריפט ממוקמים בהקשר הגלובלי, לצד שירותי Apps Script המובנים ורכיבי ECMAScript מובנים כמו Math ו-Date.

כשמעבירים את הסקריפט ל-V8, צריך לבדוק את הציפיות של הקוד לגבי השימוש ב-this בהקשר גלובלי ולהתאים אותן. ברוב המקרים, ההבדלים ניכרים רק אם הקוד בודק את המפתחות או את שמות המאפיינים של אובייקט this הגלובלי:

// Rhino runtime
var myGlobal = 5;

function myFunction() {

  // Only logs [myFunction, myGlobal];
  console.log(Object.keys(this));

  // Only logs [myFunction, myGlobal];
  console.log(
    Object.getOwnPropertyNames(this));
}





      
// V8 runtime
var myGlobal = 5;

function myFunction() {

  // Logs an array that includes the names
  // of Apps Script services
  // (CalendarApp, GmailApp, etc.) in
  // addition to myFunction and myGlobal.
  console.log(Object.keys(this));

  // Logs an array that includes the same
  // values as above, and also includes
  // ECMAScript built-ins like Math, Date,
  // and Object.
  console.log(
    Object.getOwnPropertyNames(this));
}

שינוי הטיפול ב-instanceof בספריות

שימוש ב-instanceof בספרייה באובייקט שמועבר כפרמטר בפונקציה מפרויקט אחר עלול להחזיר תוצאות שליליות שגויות. בזמן הריצה של V8, פרויקט והספריות שלו מורצים בהקשרים שונים של ביצוע, ולכן יש להם משתנים גלובליים שונים ושרשראות אב-טיפוס שונות.

זה קורה רק אם בספרייה שלכם נעשה שימוש ב-instanceof באובייקט שלא נוצר בפרויקט. השימוש בו באובייקט שנוצר בפרויקט, בין אם באותו סקריפט או בסקריפט אחר בתוך הפרויקט, אמור לפעול כמצופה.

אם פרויקט שפועל ב-V8 משתמש בסקריפט שלכם כספרייה, בדקו אם הסקריפט משתמש ב-instanceof בפרמטר שמועבר מפרויקט אחר. כדאי לשנות את השימוש ב-instanceof ולהשתמש בחלופות אחרות שמתאימות לתרחיש השימוש שלכם.

אפשרות חלופית ל-a instanceof b היא להשתמש בבונה של a במקרים שבהם לא צריך לחפש בשרשרת האב טיפוס כולה, אלא רק לבדוק את הבונה. שימוש: a.constructor.name == "b"

נניח שיש פרויקט א' ופרויקט ב', ופרויקט א' משתמש בפרויקט ב' כספרייה.

//Rhino runtime

//Project A

function caller() {
   var date = new Date();
   // Returns true
   return B.callee(date);
}

//Project B

function callee(date) {
   // Returns true
   return(date instanceof Date);
}

      
//V8 runtime

//Project A

function caller() {
   var date = new Date();
   // Returns false
   return B.callee(date);
}

//Project B

function callee(date) {
   // Incorrectly returns false
   return(date instanceof Date);
   // Consider using return (date.constructor.name ==
   // Date) instead.
   // return (date.constructor.name == Date) -> Returns
   // true
}

אפשרות נוספת היא להוסיף פונקציה שבודקת את instanceof בפרויקט הראשי, ולהעביר את הפונקציה בנוסף לפרמטרים אחרים כשקוראים לפונקציית ספרייה. אחר כך אפשר להשתמש בפונקציה שהועברה כדי לבדוק את instanceof בספרייה.

//V8 runtime

//Project A

function caller() {
   var date = new Date();
   // Returns True
   return B.callee(date, date => date instanceof Date);
}

//Project B

function callee(date, checkInstanceOf) {
  // Returns True
  return checkInstanceOf(date);
}
      

שינוי העברת משאבים לא משותפים לספריות

העברת משאב לא משותף מסקריפט ראשי לספרייה פועלת בצורה שונה בסביבת זמן הריצה של V8.

בזמן הריצה של Rhino, אי אפשר להעביר משאב לא משותף. במקום זאת, הספרייה משתמשת במשאב משלה.

בזמן הריצה של V8, העברת משאב לא משותף לספרייה פועלת. הספרייה משתמשת במשאב הלא משותף שהועבר.

אל תעבירו משאבים לא משותפים כפרמטרים של פונקציות. תמיד צריך להצהיר על משאבים לא משותפים באותו סקריפט שמשתמש בהם.

נניח שיש פרויקט א' ופרויקט ב', ופרויקט א' משתמש בפרויקט ב' כספרייה. בדוגמה הזו, PropertiesService הוא משאב לא משותף.

// Rhino runtime
// Project A
function testPassingNonSharedProperties() {
  PropertiesService.getScriptProperties()
      .setProperty('project', 'Project-A');
  B.setScriptProperties();
  // Prints: Project-B
  Logger.log(B.getScriptProperties(
      PropertiesService, 'project'));
}

//Project B function setScriptProperties() { PropertiesService.getScriptProperties() .setProperty('project', 'Project-B'); } function getScriptProperties( propertiesService, key) { return propertiesService.getScriptProperties() .getProperty(key); }

// V8 runtime
// Project A
function testPassingNonSharedProperties() {
  PropertiesService.getScriptProperties()
      .setProperty('project', 'Project-A');
  B.setScriptProperties();
  // Prints: Project-A
  Logger.log(B.getScriptProperties(
      PropertiesService, 'project'));
}

// Project B function setProperties() { PropertiesService.getScriptProperties() .setProperty('project', 'Project-B'); } function getScriptProperties( propertiesService, key) { return propertiesService.getScriptProperties() .getProperty(key); }

המלצות ל-JDBC בסביבת זמן ריצה V8

הוספנו תכונות חדשות לשירות JDBC באמצעות זמן הריצה V8.

שימוש במשתנה executeBatch לפעולות בקבוצות

אפשר להשתמש בפעולות executeBatch(params) כדי לבצע פעולות גורפות במסד נתונים.

בדוגמה הבאה מוצג איך להוסיף כמה שורות למסד נתונים באמצעות אצווה:

כאן מוסבר על זמן הריצה של Rhino (שיטה ישנה):

var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://...");
var stmt = conn.prepareStatement("INSERT INTO employees (name, age) VALUES (?, ?)");
var params = [["John Doe", 30], ["John Smith", 25]];
for (var i = 0; i < params.length; i++) {
  stmt.setString(1, params[i][0]);
  stmt.setInt(2, params[i][1]);
  stmt.execute();
}

הנה סביבת ההרצה V8 (שיטה חדשה):

var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://...");
var stmt = conn.prepareStatement("INSERT INTO employees (name, age) VALUES (?, ?)");
var params = [["John Doe", 30], ["John Smith", 25]];
stmt.executeBatch(params);

שימוש ב-getRows כדי לאחזר קבוצת תוצאות

משתמשים ב-getRows(queryString) כדי לאחזר נתונים של קבוצת תוצאות בשיחה אחת. המחרוזת queryString מורכבת מקריאות מופרדות בפסיקים למתודות getter של JdbcResultSet, לדוגמה: "getString(1), getDouble('price'), getDate(3, 'UTC')". השיטות הנתמכות כוללות את כל שיטות ה-getter שאחראיות לקריאת נתוני העמודות. לדוגמה, השיטות getHoldability, getMetaData וכו' לא נתמכות. הארגומנטים יכולים להיות אינדקסים של עמודות מסוג מספר שלם (מבוסס-1) או תוויות של עמודות מסוג מחרוזת עם מרכאות בודדות או כפולות.

בדוגמה הבאה אפשר לראות איך מאחזרים שורות ממערך התוצאות:

כאן מוסבר על זמן הריצה של Rhino (שיטה ישנה):

var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://...");
var stmt = conn.createStatement();
var rs = stmt.executeQuery("SELECT name, age FROM employees");
while (rs.next()) {
  Logger.log(rs.getString('name') + ", " + rs.getInt('age'));
}

הנה סביבת ההרצה V8 (שיטה חדשה):

var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://...");
var stmt = conn.createStatement();
var rs = stmt.executeQuery("SELECT name, age FROM employees");
var rows = rs.getRows("getString('name'), getInt('age')");
for (var i = 0; i < rows.length; i++) {
  Logger.log(rows[i][0] + ", " + rows[i][1]);
}

עדכון הגישה לסקריפטים עצמאיים

כדי שהטריגרים של סקריפטים עצמאיים שפועלים בסביבת זמן הריצה של V8 יפעלו כמו שצריך, צריך לתת למשתמשים לפחות הרשאת צפייה בסקריפט.